// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: authentication-free shared key and token derivation between clients
// feature: support certificate chain verification
// feature: discovery support client and server
// ------------------------------------------------------------------

#define OPENSSL_API_COMPAT 10101

#include <openssl/opensslv.h>
#include <openssl/md5.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/obj_mac.h>
#include <openssl/rand.h>
#include <edds/rtps/security/logging/Logging.h>
#include <edds/rtps/messages/CDRMessage.h>
#include <edds/rtps/builtin/data/ParticipantProxyData.h>
#include <security/authentication/PKIDH.h>
#include <security/authentication/PKIIdentityHandle.h>
#include <cassert>
#include <algorithm>
#include <fstream>
#include <limits>
#include <string>
#include <vector>
#include <utility>
#include <elog/Log.hpp>
#include <edds/dds/core/policy/ParameterList.hpp>
#include <security/artifact_providers/FileProvider.hpp>
#include <security/artifact_providers/Pkcs11Provider.hpp>

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
#define IS_OPENSSL_1_1 1
#define OPENSSL_CONST const
#else
#define IS_OPENSSL_1_1 0
#define OPENSSL_CONST
#endif  // if OPENSSL_VERSION_NUMBER >= 0x10100000L

#if OPENSSL_VERSION_NUMBER >= 0x10101040L
#define IS_OPENSSL_1_1_1d 1
#else
#define IS_OPENSSL_1_1_1d 0
#endif  // if OPENSSL_VERSION_NUMBER >= 0x10101040L

#define S1(x) #x
#define S2(x) S1(x)
#define LOCATION " (" __FILE__ ":" S2(__LINE__) ")"
#define _SecurityException_(str) SecurityException(std::string(str) + LOCATION)

#define PUBKEY_PEM_SIZE 113
#define PUBKEY_BASE64_SIZE 44
#define PUBKEY_PREFIX_SIZE 12
#define PUBKEY_SIZE 32
static char pubkey_prefix[PUBKEY_PREFIX_SIZE] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03,
                                                 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00};

namespace evbs {
namespace ertps {
namespace rtps {

using namespace security;

using ParameterList = evbs::edds::dds::ParameterList;

#if VBSAUTH
using vbs::security::auth::MVBS_AES_KEY_ID;
using vbs::security::auth::VBSAuthErrorCode;
using vbs::security::auth::VBSAuthManager;
VBSAuthManager& PKIDH::vbsauth = VBSAuthManager::instance();
#endif

#define MVBS_SEC_Q_LEN 16
// mvbs hmac
#define SHFR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))

#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))

#define SHA256_DIGEST_SIZE (256 / 8)

#define SHA256_BLOCK_SIZE (512 / 8)
#define MVBS_HMAC_KEY_SIZE 32
#define MVBS_HMAC_SIZE 64
struct sha256_ctx {
    unsigned int tot_len;
    unsigned int len;
    unsigned char block[2 * SHA256_BLOCK_SIZE];
    uint32_t h[8];
};

struct hmac_sha256_ctx {
    sha256_ctx ctx_inside;
    sha256_ctx ctx_outside;

    /* for hmac_reinit */
    sha256_ctx ctx_inside_reinit;
    sha256_ctx ctx_outside_reinit;

    unsigned char block_ipad[SHA256_BLOCK_SIZE];
    unsigned char block_opad[SHA256_BLOCK_SIZE];
};
#define UNPACK32(x, str)                     \
    {                                        \
        *((str) + 3) = (uint8_t)((x));       \
        *((str) + 2) = (uint8_t)((x) >> 8);  \
        *((str) + 1) = (uint8_t)((x) >> 16); \
        *((str) + 0) = (uint8_t)((x) >> 24); \
    }

#define PACK32(str, x)                                                                                           \
    {                                                                                                            \
        *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | ((uint32_t) * ((str) + 1) << 16) | \
               ((uint32_t) * ((str) + 0) << 24);                                                                 \
    }

/* Macros used for loops unrolling */

#define SHA256_SCR(i) \
    { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; }

#define SHA256_EXP(a, b, c, d, e, f, g, h, j)                                         \
    {                                                                                 \
        t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha256_k[j] + w[j]; \
        t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);                             \
        wv[d] += t1;                                                                  \
        wv[h] = t1 + t2;                                                              \
    }

static uint32_t sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
                                0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};

static uint32_t sha256_k[64] = {
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};

static void sha256_transf(sha256_ctx* ctx, const unsigned char* message, unsigned int block_nb) {
    uint32_t w[64];
    uint32_t wv[8];
    uint32_t t1, t2;
    const unsigned char* sub_block;
    int i;

    int j;

    for (i = 0; i < static_cast<int>(block_nb); i++) {
        sub_block = message + (i << 6);

        for (j = 0; j < 16; j++) {
            PACK32(&sub_block[j << 2], &w[j]);
        }

        for (j = 16; j < 64; j++) {
            SHA256_SCR(j);
        }

        for (j = 0; j < 8; j++) {
            wv[j] = ctx->h[j];
        }

        for (j = 0; j < 64; j++) {
            t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];
            t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
            wv[7] = wv[6];
            wv[6] = wv[5];
            wv[5] = wv[4];
            wv[4] = wv[3] + t1;
            wv[3] = wv[2];
            wv[2] = wv[1];
            wv[1] = wv[0];
            wv[0] = t1 + t2;
        }

        for (j = 0; j < 8; j++) {
            ctx->h[j] += wv[j];
        }
    }
}

static void sha256_init(sha256_ctx* ctx) {
    int i;
    for (i = 0; i < 8; i++) {
        ctx->h[i] = sha256_h0[i];
    }

    ctx->len = 0;
    ctx->tot_len = 0;
}

static void sha256_update(sha256_ctx* ctx, const unsigned char* message, unsigned int len) {
    unsigned int block_nb;
    unsigned int new_len, rem_len, tmp_len;
    const unsigned char* shifted_message;

    tmp_len = SHA256_BLOCK_SIZE - ctx->len;
    rem_len = len < tmp_len ? len : tmp_len;

    memcpy(&ctx->block[ctx->len], message, rem_len);

    if (ctx->len + len < SHA256_BLOCK_SIZE) {
        ctx->len += len;
        return;
    }

    new_len = len - rem_len;
    block_nb = new_len / SHA256_BLOCK_SIZE;

    shifted_message = message + rem_len;

    sha256_transf(ctx, ctx->block, 1);
    sha256_transf(ctx, shifted_message, block_nb);

    rem_len = new_len % SHA256_BLOCK_SIZE;

    memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len);

    ctx->len = rem_len;
    ctx->tot_len += (block_nb + 1) << 6;
}

static void sha256_final(sha256_ctx* ctx, unsigned char* digest) {
    unsigned int block_nb;
    unsigned int pm_len;
    unsigned int len_b;

    int i;

    block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)));

    len_b = (ctx->tot_len + ctx->len) << 3;
    pm_len = block_nb << 6;

    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
    ctx->block[ctx->len] = 0x80;
    UNPACK32(len_b, ctx->block + pm_len - 4);

    sha256_transf(ctx, ctx->block, block_nb);

    for (i = 0; i < 8; i++) {
        UNPACK32(ctx->h[i], &digest[i << 2]);
    }
}

static void hmac_sha256_init(hmac_sha256_ctx* ctx, const unsigned char* key, unsigned int key_size) {
    unsigned int fill;
    unsigned int num;

    const unsigned char* key_used;
    unsigned char key_temp[SHA256_DIGEST_SIZE];
    int i;

    if (key_size == SHA256_BLOCK_SIZE) {
        key_used = key;
        num = SHA256_BLOCK_SIZE;
    } else {
        if (key_size > SHA256_BLOCK_SIZE) {
            num = SHA256_DIGEST_SIZE;
            (void)SHA256(key, key_size, key_temp);
            key_used = key_temp;
        } else { /* key_size > SHA256_BLOCK_SIZE */
            key_used = key;
            num = key_size;
        }
        fill = SHA256_BLOCK_SIZE - num;

        memset(ctx->block_ipad + num, 0x36, fill);
        memset(ctx->block_opad + num, 0x5c, fill);
    }

    for (i = 0; i < static_cast<int>(num); i++) {
        ctx->block_ipad[i] = key_used[i] ^ 0x36;
        ctx->block_opad[i] = key_used[i] ^ 0x5c;
    }

    sha256_init(&ctx->ctx_inside);
    sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE);

    sha256_init(&ctx->ctx_outside);
    sha256_update(&ctx->ctx_outside, ctx->block_opad, SHA256_BLOCK_SIZE);

    /* for hmac_reinit */
    memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, sizeof(sha256_ctx));
    memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, sizeof(sha256_ctx));
}

// static void hmac_sha256_reinit(hmac_sha256_ctx *ctx)
// {
//  memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit,
//         sizeof(sha256_ctx));
//  memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit,
//         sizeof(sha256_ctx));
// }

static void hmac_sha256_update(hmac_sha256_ctx* ctx, const unsigned char* message, unsigned int message_len) {
    sha256_update(&ctx->ctx_inside, message, message_len);
}

static void hmac_sha256_final(hmac_sha256_ctx* ctx, unsigned char* mac) {
    unsigned char digest_inside[SHA256_DIGEST_SIZE];
    unsigned char mac_temp[SHA256_DIGEST_SIZE];

    sha256_final(&ctx->ctx_inside, digest_inside);
    sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE);
    sha256_final(&ctx->ctx_outside, mac_temp);
    memcpy(mac, mac_temp, SHA256_DIGEST_SIZE);
}

static void hmac_sha256(const unsigned char* key, unsigned int key_size, const unsigned char* message,
                        unsigned int message_len, unsigned char* mac) {
    hmac_sha256_ctx ctx;

    hmac_sha256_init(&ctx, key, key_size);
    hmac_sha256_update(&ctx, message, message_len);
    hmac_sha256_final(&ctx, mac);
}

bool PKIDH::mvbs_hmac_message(const std::vector<uint8_t>& pkey, const std::vector<uint8_t>& message,
                              std::vector<uint8_t>& sign_data, SecurityException& exception) {
    if (pkey.size() != MVBS_HMAC_KEY_SIZE) {
        exception = _SecurityException_("mvbs hmac key size error:" + pkey.size());
        return false;
    }
    sign_data.resize(MVBS_HMAC_SIZE);
    hmac_sha256(pkey.data(), pkey.size(), message.data(), message.size(), sign_data.data());

    return true;
}

bool PKIDH::mvbs_hmac_verify_message(const std::vector<uint8_t>& pkey, const std::vector<uint8_t>& message,
                                     const std::vector<uint8_t>& sign_data, SecurityException& exception) {
    if (pkey.size() != MVBS_HMAC_KEY_SIZE || sign_data.size() != MVBS_HMAC_SIZE) {
        exception = _SecurityException_("mvbs hmac key size error");
        return false;
    }

    std::vector<uint8_t> sign_data_(MVBS_HMAC_SIZE, 0);

    if (!mvbs_hmac_message(pkey, message, sign_data_, exception)) {
        return false;
    }

    if (!std::equal(sign_data_.begin(), sign_data_.begin() + 32, sign_data.begin())) {
        exception = _SecurityException_("mvbs hmac verify error");
        return false;
    }

    return true;
}

bool PKIDH::mvbs_hmac_sha256(const unsigned char* data, const size_t length, std::vector<uint8_t>& mac,
                             SecurityException& exception) {
    assert(data);
    (void)length;
    (void)mac;
    (void)exception;
    bool returnedValue = false;

#if VBSAUTH
    int ret = PKIDH::vbsauth.hmacSha256(MVBS_AES_KEY_ID::NO_KEY, data, length, mac);
    if (ret != VBSAuthErrorCode::NONE_ERROR) {
        exception = _SecurityException_(std::string("vbsauth hmacsha256 error") + std::to_string(ret));
    } else {
        returnedValue = true;
    }
#endif

    return returnedValue;
}
// mvbs hamc end

static const unsigned char* BN_deserialize_raw(BIGNUM** bn, const unsigned char* raw_pointer, size_t length,
                                               SecurityException& exception) {
    BIGNUM* bnn = BN_new();

    if (bnn != nullptr) {
        if (BN_bin2bn(raw_pointer, static_cast<int>(length), bnn) != nullptr) {
            *bn = bnn;
            return raw_pointer + length;
        } else {
            exception = _SecurityException_("Cannot deserialize DH");
        }

        BN_free(bnn);
    } else {
        exception = _SecurityException_("OpenSSL library cannot create bignum");
    }

    return nullptr;
}

static bool get_signature_algorithm(X509* certificate, std::string& signature_algorithm, SecurityException& exception) {
    bool returnedValue = false;
    BUF_MEM* ptr = nullptr;
    OPENSSL_CONST X509_ALGOR* sigalg = nullptr;
    OPENSSL_CONST ASN1_BIT_STRING* sig = nullptr;

    BIO* out = BIO_new(BIO_s_mem());

    if (out != nullptr) {
        X509_get0_signature(&sig, &sigalg, certificate);

        if (sigalg != nullptr) {
            if (i2a_ASN1_OBJECT(out, sigalg->algorithm) > 0) {
                (void)BIO_get_mem_ptr(out, &ptr);

                if (ptr != nullptr) {
                    if (strncmp(ptr->data, "ecdsa-with-SHA256", ptr->length) == 0) {
                        signature_algorithm = evbs::ertps::rtps::security::ECDSA_SHA256;
                        returnedValue = true;
                    } else if (strncmp(ptr->data, "sha256WithRSAEncryption", ptr->length) == 0) {
                        signature_algorithm = evbs::ertps::rtps::security::RSA_SHA256;
                        returnedValue = true;
                    } else if (strncmp(ptr->data, "sha1WithRSAEncryption", ptr->length) == 0) {
                        signature_algorithm = evbs::ertps::rtps::security::RSA_SHA256;
                        returnedValue = true;
                    } else if (strncmp(ptr->data, "ecdsa-with-SHA384", ptr->length) == 0) {
                        signature_algorithm = evbs::ertps::rtps::security::ECDSA_SHA384;
                        returnedValue = true;
                    }
                } else {  // LCOV_EXCL_START
                    exception = _SecurityException_("OpenSSL library cannot retrieve mem ptr");
                }
            }
        } else {
            exception = _SecurityException_("OpenSSL library cannot write cert");
        }

        (void)BIO_free(out);
    } else {
        exception = _SecurityException_("OpenSSL library cannot allocate mem");
    }  // LCOV_EXCL_STOP

    return returnedValue;
}

// Auxiliary functions
static X509_STORE* load_identity_ca(const std::string& identity_ca, bool& there_are_crls, std::string& ca_sn,
                                    std::string& ca_algo, SecurityException& exception) {
    if ((identity_ca.size() >= 7) && (identity_ca.compare(0, 7, "file://") == 0)) {
        return evbs::ertps::rtps::security::detail::FileProvider::load_ca(identity_ca, there_are_crls, ca_sn, ca_algo,
                                                                          get_signature_algorithm, exception);
    }
#if VBSAUTH
    else if ((identity_ca.size() >= 12) && (identity_ca.compare(0, 12, "liddsauth://") == 0)) {
        std::string ca;
        if (PKIDH::vbsauth.loadCA(ca) != VBSAuthErrorCode::NONE_ERROR) {
            exception = _SecurityException_(std::string("VBSAUTH load ca failed ") + identity_ca);
            return nullptr;
        }

        return evbs::ertps::rtps::security::detail::FileProvider::load_ca_from_string(
            ca, there_are_crls, ca_sn, ca_algo, get_signature_algorithm, exception);
    }
#endif
    exception = _SecurityException_(std::string("Unsupported URI format ") + identity_ca);
    return nullptr;
}

static X509* load_certificate(const std::string& identity_cert, STACK_OF(X509) * *intermediate_certs,
                              SecurityException& exception) {
    if ((identity_cert.size() >= 7) && (identity_cert.compare(0, 7, "file://") == 0)) {
        return evbs::ertps::rtps::security::detail::FileProvider::load_certificate(identity_cert, exception);
    }
#if VBSAUTH
    else if ((identity_cert.size() >= 12) && (identity_cert.compare(0, 12, "liddsauth://") == 0)) {
        std::string cert;
        if (PKIDH::vbsauth.loadCertificate(cert) != VBSAuthErrorCode::NONE_ERROR) {
            exception = _SecurityException_(std::string("VBSAUTH load cert failed ") + identity_cert);
            return nullptr;
        }
        return evbs::ertps::rtps::security::detail::FileProvider::load_certificate_from_string(cert, intermediate_certs,
                                                                                               exception);
    }
#else
    (void)intermediate_certs;
#endif
    exception = _SecurityException_(std::string("Unsupported URI format ") + identity_cert);
    return nullptr;
}

static X509* load_certificate(const std::vector<uint8_t>& data, STACK_OF(X509) * *intermediate_certs) {
    X509* returnedValue = nullptr;

    if (data.size() <= static_cast<size_t>(std::numeric_limits<int>::max())) {
        BIO* cid = BIO_new_mem_buf(data.data(), static_cast<int>(data.size()));

        if (cid != nullptr) {
            returnedValue = PEM_read_bio_X509_AUX(cid, NULL, NULL, NULL);
            X509* cert = nullptr;
            *intermediate_certs = sk_X509_new_null();

            while ((cert = PEM_read_bio_X509_AUX(cid, nullptr, nullptr, nullptr))) {
                sk_X509_push(*intermediate_certs, cert);  // 中间证书链
            }
            (void)BIO_free(cid);
        }
    }

    return returnedValue;
}

EVP_PKEY* load_ed25519_privatekey(const std::string& filename) {
    EVP_PKEY* pPrivateKey = NULL;
    if ((filename.size() >= 7) && (filename.compare(0, 7, "file://") == 0)) {
        FILE* pFile = fopen(filename.substr(7).c_str(), "r");
        if (!pFile) {
            return NULL;
        }

        pPrivateKey = PEM_read_PrivateKey(pFile, NULL, NULL, NULL);
        fclose(pFile);
    }

    return pPrivateKey;
}

EVP_PKEY* load_ed25519_publickey(const std::string& filename) {
    EVP_PKEY* pPublicKey = NULL;

    if ((filename.size() >= 7) && (filename.compare(0, 7, "file://") == 0)) {
        FILE* pFile = fopen(filename.substr(7).c_str(), "r");
        if (!pFile) {
            return NULL;
        }

        pPublicKey = PEM_read_PUBKEY(pFile, NULL, NULL, NULL);
        fclose(pFile);
    }

    return pPublicKey;
}

static bool load_mvbs_hmac_key(const std::string& filename, std::vector<uint8_t>& mhmac_key) {
    if ((filename.size() >= 7) && (filename.compare(0, 7, "file://") == 0)) {
        std::ifstream file(filename.substr(7).c_str(), std::ios::binary);

        // 检查文件是否成功打开
        if (!file.is_open()) {
            return false;
        }

        // 从文件读取字节并存储到 vector 中
        unsigned char byte;
        while (file.read(reinterpret_cast<char*>(&byte), sizeof(unsigned char))) {
            mhmac_key.push_back(byte);
        }

        // 关闭文件
        file.close();

        if (mhmac_key.size() != 20) {
            return false;
        }
        std::cout << "hamc key: ";
        for (unsigned char value : mhmac_key) {
            std::cout << static_cast<int>(value) << " ";
        }
        std::cout << std::endl;
        return true;
    }

    return false;
}

// 验证回调函数
int verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
    int err = X509_STORE_CTX_get_error(ctx);

    if (err != X509_V_OK) {
        // 打印当前校验错误
        logWarning(SECURITY_AUTHENTICATION,
                   "Verification depth: " << X509_STORE_CTX_get_error_depth(ctx) << ", Error code: " << err
                                          << ", Message: " << X509_verify_cert_error_string(err));
    }

    // 忽略 Name Constraints 违规
    if (err == X509_V_ERR_PERMITTED_VIOLATION) {
        logWarning(SECURITY_AUTHENTICATION, "Ignoring Name Constraints violation...");
        return 1;  // 强制通过校验
    }

    // 对其他错误保持默认处理逻辑
    return preverify_ok;
}

static bool verify_certificate(X509_STORE* store, X509* cert, const bool there_are_crls,
                               STACK_OF(X509) * intermediate_certs, SecurityException& exception) {
    assert(store);
    assert(cert);

    bool returnedValue = false;

    X509_STORE_CTX* ctx = X509_STORE_CTX_new();
    if (!ctx) {
        logWarning(SECURITY_AUTHENTICATION, "Invalidation error of certificate, X509_STORE_CTX create failed.");
        exception = _SecurityException_("Invalidation error of certificate, X509_STORE_CTX create failed.");
        return returnedValue;
    }

    unsigned long flags = there_are_crls ? X509_V_FLAG_CRL_CHECK : 0;
    if (X509_STORE_CTX_init(ctx, store, cert, intermediate_certs) > 0) {
        X509_STORE_CTX_set_flags(ctx, flags | /*X509_V_FLAG_X509_STRICT |*/
                                          X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME |
                                          X509_V_FLAG_POLICY_CHECK);

        X509_STORE_CTX_set_verify_cb(ctx, verify_callback);
        if (X509_verify_cert(ctx) > 0) {
            returnedValue = true;
        } else {
            int errorCode = X509_STORE_CTX_get_error(ctx);
            if (errorCode == X509_V_OK) {
                logWarning(SECURITY_AUTHENTICATION, "Invalidation error of certificate, but no error code returned.");
                exception = _SecurityException_("Invalidation error of certificate, but no error code returned.");
            } else {
                logWarning(SECURITY_AUTHENTICATION,
                           "Invalidation error of certificate  (" << X509_verify_cert_error_string(errorCode) << ")");
                exception =
                    _SecurityException_(std::string("Invalidation error of certificate  (") +
                                        std::string(X509_verify_cert_error_string(errorCode)) + std::string(")"));
            }
        }

        X509_STORE_CTX_cleanup(ctx);
    } else {
        logWarning(SECURITY_AUTHENTICATION, "Cannot init context for verifying certificate");
        exception = _SecurityException_("Cannot init context for verifying certificate");
    }

    X509_STORE_CTX_free(ctx);

    return returnedValue;
}

static EVP_PKEY* load_private_key(X509* certificate, const std::string& file, const std::string& password,
                                  SecurityException& exception, PKIDH& pkidh) {
    EVP_PKEY* key = nullptr;

    if ((file.size() >= 7) && (file.compare(0, 7, "file://") == 0)) {
        key =
            evbs::ertps::rtps::security::detail::FileProvider::load_private_key(certificate, file, password, exception);
#if VBSAUTH
    } else if ((file.size() >= 12) && (file.compare(0, 12, "liddsauth://") == 0)) {
        // do nothing, private key is protected in vbsauth
#endif
    } else if ((file.size() >= 7) && (file.compare(0, 7, "pkcs11:") == 0)) {  // LCOV_EXCL_START
        if (!pkidh.pkcs11_provider) {
            pkidh.pkcs11_provider.reset(new evbs::ertps::rtps::security::detail::Pkcs11Provider());
        }

        key = pkidh.pkcs11_provider->load_private_key(certificate, file, password, exception);
    } else {
        exception = _SecurityException_(std::string("Unsupported URI format ") + file);
    }  // LCOV_EXCL_STOP

    return key;
}

static bool store_certificate_in_buffer(X509* certificate, STACK_OF(X509) * intermediate_certs, BUF_MEM** ptr,
                                        SecurityException& exception) {
    bool returnedValue = false;

    BIO* out = BIO_new(BIO_s_mem());

    if (out != nullptr) {
        if (PEM_write_bio_X509(out, certificate) > 0) {
            bool success = true;
            int num_certs = sk_X509_num(intermediate_certs);

            for (int i = 0; i < num_certs; i++) {
                X509* cert = sk_X509_value(intermediate_certs, i);
                if (PEM_write_bio_X509(out, cert) <= 0) {
                    exception = _SecurityException_("OpenSSL library cannot write cert");
                    success = false;
                    break;
                }
            }

            if (success) {
                BIO_get_mem_ptr(out, ptr);
                if (*ptr != nullptr) {
                    (void)BIO_set_close(out, BIO_NOCLOSE);
                    returnedValue = true;
                } else {  // LCOV_EXCL_START
                    exception = _SecurityException_("OpenSSL library cannot retrieve mem ptr");
                }
            }
        } else {
            exception = _SecurityException_("OpenSSL library cannot write cert");
        }

        (void)BIO_free(out);
    } else {
        exception = _SecurityException_("OpenSSL library cannot allocate mem");
    }  // LCOV_EXCL_STOP

    return returnedValue;
}

static bool sign_sha256(EVP_PKEY* private_key, const unsigned char* data, const size_t data_length,
                        std::vector<uint8_t>& signature, SecurityException& exception, PKIDH& pkidh) {
    (void)pkidh;
    assert(data);
    bool returnedValue = false;
#if VBSAUTH
    if (pkidh.is_use_vbsauth) {
        int ret = PKIDH::vbsauth.signSha256(data, data_length, signature);
        if (ret != VBSAuthErrorCode::NONE_ERROR || signature.size() > 512) {
            exception = _SecurityException_(std::string("vbsauth sign error") + std::to_string(ret));
            elogError(SECURITY, RetCode_t::RETCODE_VBSAUTH_SIGN_ERROR, "Signature computation failed");
        } else if (signature.empty()) {
            exception = _SecurityException_("vbsauth sign error: empty signature");
            elogError(SECURITY, RetCode_t::RETCODE_VBSAUTH_SIGN_ERROR, "Empty signature");
        } else if (std::all_of(signature.begin(), signature.end(), [](auto x) { return x == 0; })) {
            exception = _SecurityException_("vbsauth sign error: signature is all zeros");
            elogError(SECURITY, RetCode_t::RETCODE_VBSAUTH_SIGN_ERROR, "All-zero signature");
        } else {
            returnedValue = true;
        }

        return returnedValue;
    }
#endif
    assert(private_key);

#if IS_OPENSSL_1_1
    EVP_MD_CTX* ctx = EVP_MD_CTX_new();
#else
    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(malloc(sizeof(EVP_MD_CTX)));
#endif  // if IS_OPENSSL_1_1
    (void)EVP_MD_CTX_init(ctx);
    EVP_PKEY_CTX* pkey;

    auto md = EVP_sha256();
    if (EVP_DigestSignInit(ctx, &pkey, md, NULL, private_key) == 1) {
        // TODO(Miguel): don't do this for ECDSA
        (void)EVP_PKEY_CTX_set_rsa_padding(pkey, RSA_PKCS1_PSS_PADDING);
        (void)EVP_PKEY_CTX_set_rsa_mgf1_md(pkey, md);
        (void)EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey, -1);

        if (EVP_DigestSignUpdate(ctx, data, data_length) == 1) {
            size_t length = 0;
            if ((EVP_DigestSignFinal(ctx, NULL, &length) == 1) && (length > 0)) {
                signature.resize(length);

                if (EVP_DigestSignFinal(ctx, signature.data(), &length) == 1) {
                    signature.resize(length);
                    returnedValue = true;
                } else {  // LCOV_EXCL_START
                    exception = _SecurityException_(std::string("Cannot finish signature (") +
                                                    std::to_string(ERR_get_error()) + std::string(")"));
                }
            } else {
                exception = _SecurityException_(std::string("Cannot retrieve signature length (") +
                                                std::to_string(ERR_get_error()) + std::string(")"));
            }
        } else {
            exception = _SecurityException_(std::string("Cannot sign data (") + std::to_string(ERR_get_error()) +
                                            std::string(")"));
        }
    } else {
        exception = _SecurityException_(std::string("Cannot init signature (") + std::to_string(ERR_get_error()) +
                                        std::string(")"));
    }  // LCOV_EXCL_STOP

#if IS_OPENSSL_1_1
    EVP_MD_CTX_free(ctx);
#else
    EVP_MD_CTX_cleanup(ctx);
    free(ctx);
#endif  // if IS_OPENSSL_1_1

    return returnedValue;
}

static bool check_sign_sha256(X509* certificate, const unsigned char* data, const size_t data_length,
                              const std::vector<uint8_t>& signature, SecurityException& exception) {
    assert(certificate);
    assert(data);

    bool returnedValue = false;

    EVP_MD_CTX* ctx =
#if IS_OPENSSL_1_1
        EVP_MD_CTX_new();
#else
        reinterpret_cast<EVP_MD_CTX*>(malloc(sizeof(EVP_MD_CTX)));
#endif  // if IS_OPENSSL_1_1
    (void)EVP_MD_CTX_init(ctx);

    EVP_PKEY* pubkey = X509_get_pubkey(certificate);

    if (pubkey != nullptr) {
        auto md = EVP_sha256();
        EVP_PKEY_CTX* pkey;
        if (EVP_DigestVerifyInit(ctx, &pkey, md, NULL, pubkey) == 1) {
            // TODO(Miguel): don't do this for ECDSA
            (void)EVP_PKEY_CTX_set_rsa_padding(pkey, RSA_PKCS1_PSS_PADDING);
            (void)EVP_PKEY_CTX_set_rsa_mgf1_md(pkey, md);
            (void)EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey, -2);

            if (EVP_DigestVerifyUpdate(ctx, data, data_length) == 1) {
                if (EVP_DigestVerifyFinal(ctx, signature.data(), signature.size()) == 1) {
                    returnedValue = true;
                } else {  // LCOV_EXCL_START
                    logWarning(SECURITY_AUTHENTICATION, "Signature verification error (" << ERR_get_error() << ")");
                    exception = _SecurityException_(std::string("Signature verification error (") +
                                                    std::to_string(ERR_get_error()) + std::string(")"));
                }
            } else {
                exception = _SecurityException_(std::string("Cannot update signature check (") +
                                                std::to_string(ERR_get_error()) + std::string(")"));
            }

        } else {
            exception = _SecurityException_(std::string("Cannot init signature check (") +
                                            std::to_string(ERR_get_error()) + std::string(")"));
        }

        EVP_PKEY_free(pubkey);
    } else {
        exception = _SecurityException_("Cannot get public key from certificate");
    }  // LCOV_EXCL_STOP

#if IS_OPENSSL_1_1
    EVP_MD_CTX_free(ctx);
#else
    EVP_MD_CTX_cleanup(ctx);
    free(ctx);
#endif  // if IS_OPENSSL_1_1

    return returnedValue;
}

static X509_CRL* load_crl(const std::string& identity_crl, SecurityException& exception) {
    if ((identity_crl.size() >= 7) && (identity_crl.compare(0, 7, "file://") == 0)) {
        return evbs::ertps::rtps::security::detail::FileProvider::load_crl(identity_crl, exception);
    }
#if VBSAUTH
    else if ((identity_crl.size() >= 12) && (identity_crl.compare(0, 12, "liddsauth://") == 0)) {
        std::string crls;
        if (PKIDH::vbsauth.loadCRL(crls) != VBSAuthErrorCode::NONE_ERROR) {
            exception = _SecurityException_(std::string("VBSAUTH load crl failed ") + identity_crl);
            return nullptr;
        }

        return evbs::ertps::rtps::security::detail::FileProvider::load_crl_from_string(crls, exception);
    }
#endif
    exception = _SecurityException_(std::string("Unsupported URI format ") + identity_crl);
    return nullptr;
}

static bool adjust_participant_key(X509* cert, const GUID_t& candidate_participant_key,
                                   GUID_t& adjusted_participant_key, SecurityException& exception) {
    assert(cert != nullptr);

    X509_NAME* cert_sn = X509_get_subject_name(cert);
    assert(cert_sn != nullptr);

    unsigned char md[SHA256_DIGEST_LENGTH];
    uint32_t length = 0;

    if ((!X509_NAME_digest(cert_sn, EVP_sha256(), md, &length)) || (length != SHA256_DIGEST_LENGTH)) {
        exception = _SecurityException_("OpenSSL library cannot hash sha256");
        return false;
    }

    adjusted_participant_key.guidPrefix.value[0] = candidate_participant_key.guidPrefix.value[0];
    adjusted_participant_key.guidPrefix.value[1] = candidate_participant_key.guidPrefix.value[1];
    adjusted_participant_key.guidPrefix.value[2] = candidate_participant_key.guidPrefix.value[2];
    adjusted_participant_key.guidPrefix.value[3] = candidate_participant_key.guidPrefix.value[3];
    // 4-7 is used for pid
    adjusted_participant_key.guidPrefix.value[4] = candidate_participant_key.guidPrefix.value[4];
    adjusted_participant_key.guidPrefix.value[5] = candidate_participant_key.guidPrefix.value[5];
    adjusted_participant_key.guidPrefix.value[6] = candidate_participant_key.guidPrefix.value[6];
    adjusted_participant_key.guidPrefix.value[7] = candidate_participant_key.guidPrefix.value[7];

    // adjusted_participant_key.guidPrefix.value[8] = 0x80 | (md[0] >> 1);
    // adjusted_participant_key.guidPrefix.value[9] = (md[0] << 7) | (md[1] >> 1);
    // adjusted_participant_key.guidPrefix.value[10] = (md[1] << 7) | (md[2] >> 1);
    // adjusted_participant_key.guidPrefix.value[11] = (md[2] << 7) | (md[3] >> 1);
    // 8-11 is used for participant_id
    adjusted_participant_key.guidPrefix.value[8] = candidate_participant_key.guidPrefix.value[8];
    adjusted_participant_key.guidPrefix.value[9] = candidate_participant_key.guidPrefix.value[9];
    adjusted_participant_key.guidPrefix.value[10] = candidate_participant_key.guidPrefix.value[10];
    adjusted_participant_key.guidPrefix.value[11] = candidate_participant_key.guidPrefix.value[11];

    unsigned char key[16] = {
        candidate_participant_key.guidPrefix.value[0],  candidate_participant_key.guidPrefix.value[1],
        candidate_participant_key.guidPrefix.value[2],  candidate_participant_key.guidPrefix.value[3],
        candidate_participant_key.guidPrefix.value[4],  candidate_participant_key.guidPrefix.value[5],
        candidate_participant_key.guidPrefix.value[6],  candidate_participant_key.guidPrefix.value[7],
        candidate_participant_key.guidPrefix.value[8],  candidate_participant_key.guidPrefix.value[9],
        candidate_participant_key.guidPrefix.value[10], candidate_participant_key.guidPrefix.value[11],
        candidate_participant_key.entityId.value[0],    candidate_participant_key.entityId.value[1],
        candidate_participant_key.entityId.value[2],    candidate_participant_key.entityId.value[3]};

    if (!EVP_Digest(&key, 16, md, NULL, EVP_sha256(), NULL)) {
        exception = _SecurityException_("OpenSSL library cannot hash sha256");
        return false;
    }

    // adjusted_participant_key.guidPrefix.value[10] = md[0];
    // adjusted_participant_key.guidPrefix.value[11] = md[1];

    adjusted_participant_key.entityId.value[0] = candidate_participant_key.entityId.value[0];
    adjusted_participant_key.entityId.value[1] = candidate_participant_key.entityId.value[1];
    adjusted_participant_key.entityId.value[2] = candidate_participant_key.entityId.value[2];
    adjusted_participant_key.entityId.value[3] = candidate_participant_key.entityId.value[3];

    return true;
}

static int get_dh_type(const std::string& algorithm) {
    auto raw_alg = algorithm.c_str();
    if (strcmp(evbs::ertps::rtps::security::DH_2048_256, raw_alg) == 0) {
        return EVP_PKEY_DH;
    } else if (strcmp(evbs::ertps::rtps::security::ECDH_prime256v1, raw_alg) == 0) {
        return EVP_PKEY_EC;
    }

    return 0;
}

// static bool coverPemtovector(EVP_PKEY *pkey, std::vector<uint8_t> &pkeytouint8, SecurityException& exception) {
//     BIO *bio = BIO_new(BIO_s_mem());
//     if (!bio) {
//         exception = _SecurityException_("Failed to create BIO");
//         return false;
//     }

//     if (!PEM_write_bio_PUBKEY(bio, pkey)) {
//         BIO_free(bio);
//         exception = _SecurityException_("Failed to write public key to BIO");
//         return false;
//     }

//     int keylen = BIO_pending(bio);
//     // pkeytouint8.resize(keylen + 1);
//     // pkeytouint8[keylen] = '\0';
//     pkeytouint8.resize(keylen);
//     BIO_read(bio, pkeytouint8.data(), keylen);

//     BIO_free(bio);
//     return true;
// }

// EVP_PKEY* coverVectortoPem(const std::vector<unsigned char>& key, SecurityException& exception) {
//     BIO *bio = BIO_new_mem_buf(key.data(), key.size());
//     if (!bio) {
//         exception = _SecurityException_("Failed to create BIO");
//         return NULL;
//     }

//     EVP_PKEY *pkey = NULL;

//     pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);

//     if (!pkey) {
//         BIO_free(bio);
//         exception = _SecurityException_("Failed to read public key from BIO");
//         return NULL;
//     }

//     BIO_free(bio);
//     return pkey;
// }

int pubkey_bytes2pem(const void* key_buf, int key_size, char* str_buff, int str_size) {
    (void)key_size;

    if (str_size < PUBKEY_PEM_SIZE) {
        printf("pem buff is too short\n");
        return -1;
    }

    unsigned char key[PUBKEY_BASE64_SIZE + 1] = {0};
    int key_len = PUBKEY_BASE64_SIZE;
    unsigned char out[61] = {0};

    if (key_len >= static_cast<int>(sizeof(pubkey_prefix))) {
        memcpy(key, pubkey_prefix, sizeof(pubkey_prefix));
        key_len -= sizeof(pubkey_prefix);
    }

    if (key_len >= key_size) {
        memcpy(key + sizeof(pubkey_prefix), key_buf, key_size);
    } else {
        std::cout << "stack-buffer-overflow" << std::endl;
        return -1;
    }

    BIO* bio = BIO_new(BIO_f_base64());
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    (void)BIO_reset(bio);
    BIO* bmem = BIO_new(BIO_s_mem());
    (void)BIO_reset(bmem);
    bio = BIO_push(bio, bmem);

    BIO_write(bio, key, sizeof(key));
    (void)BIO_flush(bio);

    BUF_MEM* bufferPtr = nullptr;
    BIO_get_mem_ptr(bio, &bufferPtr);

    if (bufferPtr->length < 60)
        return -1;

    memcpy(&out[0], bufferPtr->data, 60);

    snprintf(str_buff, str_size, "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", &out[0]);
    // printf("cov result:%s\n", bufferPtr->data);
    BIO_free_all(bio);
    return 0;
}

static int key_pem2bytes(char* str, int offset, void* key_buff, int key_size) {
    char base64str[PUBKEY_PEM_SIZE + 1] = {0};
    char key[PUBKEY_BASE64_SIZE];

    if (key_size < PUBKEY_SIZE) {
        return -1;
    }

    sscanf(str, "%*[^\n]\n%[^\n]\n", base64str);

    BIO* bio = BIO_new(BIO_f_base64());
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    BIO* bmem = BIO_new_mem_buf(base64str, -1);
    bio = BIO_push(bio, bmem);

    int size = BIO_read(bio, key, sizeof(key));

    BIO_free_all(bio);

    if (size < 0) {
        return -1;
    }

    memcpy(key_buff, key + offset, size - offset);

    return 0;
}

int pubkey_pem2bytes(char* str, void* key_buff, int key_size) {
    return key_pem2bytes(str, PUBKEY_PREFIX_SIZE, key_buff, key_size);
}

bool coverPemtovector_base64(EVP_PKEY* publicKey, std::vector<uint8_t>& pkeytouint8, SecurityException& exception) {
    BIO* bio = BIO_new(BIO_s_mem());

    if (PEM_write_bio_PUBKEY(bio, publicKey)) {
        char* buffer;
        BIO_get_mem_data(bio, &buffer);

        pkeytouint8.resize(PUBKEY_SIZE);
        if (pubkey_pem2bytes(buffer, pkeytouint8.data(), PUBKEY_SIZE)) {
            exception = _SecurityException_("pubkey_pem2bytes failed");
            BIO_free(bio);
            return false;
        }
    }

    BIO_free(bio);

    return true;
}

EVP_PKEY* PKIDH::coverVectortoPem_base64(const std::vector<unsigned char>& key, SecurityException& exception) {
    char skey[PUBKEY_PEM_SIZE + 1] = {0};
    unsigned char buff[PUBKEY_SIZE];
    for (int i = 0; i < PUBKEY_SIZE; i++) {
        buff[i] = key[i];
    }

    pubkey_bytes2pem(buff, key.size(), skey, PUBKEY_PEM_SIZE + 1);

    BIO* bio = BIO_new_mem_buf(skey, PUBKEY_PEM_SIZE + 1);
    if (!bio) {
        exception = _SecurityException_("Failed to create BIO");
        return NULL;
    }

    EVP_PKEY* pkey = NULL;

    pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
    if (!pkey) {
        exception = _SecurityException_("Failed to read pubkey");
        BIO_free(bio);
        return NULL;
    }

    BIO_free(bio);
    return pkey;
}

constexpr size_t P_SIZE = 16;  // Replace with the actual size

void PKIDH::generate_secret_P(GUID_t guidA, GUID_t guidB, std::vector<uint8_t>& data) {
    int guid_splice_len = guidA.guidPrefix.size * 2 + guidB.entityId.size * 2;

    std::vector<unsigned char> guid_splice, mdata;
    MD5_CTX md5;

    guid_splice.insert(guid_splice.end(), guidA.guidPrefix.value, guidA.guidPrefix.value + guidA.guidPrefix.size);
    guid_splice.insert(guid_splice.end(), guidA.entityId.value, guidA.entityId.value + guidA.entityId.size);
    guid_splice.insert(guid_splice.end(), guidB.guidPrefix.value, guidB.guidPrefix.value + guidB.guidPrefix.size);
    guid_splice.insert(guid_splice.end(), guidB.entityId.value, guidB.entityId.value + guidB.entityId.size);

    mdata.resize(P_SIZE);
    MD5_Init(&md5);
    MD5_Update(&md5, guid_splice.data(), guid_splice_len);
    MD5_Final(mdata.data(), &md5);
    data.insert(data.end(), mdata.begin(), mdata.end());
}

static bool ed25519_sign_message(EVP_PKEY* pkey, const std::vector<uint8_t>& message, std::vector<uint8_t>& sign_data,
                                 SecurityException& exception) {
    EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
    const EVP_MD* md = EVP_sha512();

    std::vector<unsigned char> d_message(EVP_MAX_MD_SIZE);
    // std::vector<unsigned char> s_message;
    unsigned int d_size;
    size_t s_size;

    // LCOV_EXCL_START
    if (EVP_Digest(message.data(), message.size(), d_message.data(), &d_size, md, NULL) <= 0) {
        exception = _SecurityException_("Error in Digest Calculation");
        EVP_MD_CTX_free(mdctx);
        return false;
    }

    if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) <= 0) {
        exception = _SecurityException_("Error in DigestSign Initiation");
        EVP_MD_CTX_free(mdctx);
        return false;
    }

    if (EVP_DigestSign(mdctx, NULL, &s_size, d_message.data(), d_size) <= 0) {
        exception = _SecurityException_("Error in DigestSign Processing");
        EVP_MD_CTX_free(mdctx);
        return false;
    }

    sign_data.resize(s_size);

    if (EVP_DigestSign(mdctx, sign_data.data(), &s_size, d_message.data(), d_size) <= 0) {
        exception = _SecurityException_("Error in DigestSign Finalizing");
        EVP_MD_CTX_free(mdctx);
        return false;
    }
    // LCOV_EXCL_STOP

    EVP_MD_CTX_free(mdctx);

    return true;
}

bool PKIDH::ed25519_verify_message(EVP_PKEY* pkey, const std::vector<uint8_t>& message,
                                   const std::vector<unsigned char>& sign_data, SecurityException& exception) {
    EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
    const EVP_MD* md = EVP_sha512();

    std::vector<unsigned char> d_message(EVP_MAX_MD_SIZE);
    unsigned int d_size;

    if (EVP_Digest(message.data(), message.size(), d_message.data(), &d_size, md, NULL) <= 0) {
        exception = _SecurityException_("Error in Digest Calculation");
        EVP_MD_CTX_free(mdctx);
        return false;
    }

    if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) <= 0) {
        exception = _SecurityException_("Error in DigestVerifyInit");
        EVP_MD_CTX_free(mdctx);
        return false;
    }

    int rc = EVP_DigestVerify(mdctx, sign_data.data(), sign_data.size(), d_message.data(), d_size);
    EVP_MD_CTX_free(mdctx);

    return rc == 1;
}

static EVP_PKEY* generate_dh_key(int type, SecurityException& exception) {
    EVP_PKEY_CTX* pctx = nullptr;
    EVP_PKEY* params = nullptr;

    if (type == EVP_PKEY_EC) {
        pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
        if (pctx != nullptr) {
            if ((1 != EVP_PKEY_paramgen_init(pctx)) ||
                (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) ||
                (1 != EVP_PKEY_paramgen(pctx, &params))) {
                exception = _SecurityException_("Cannot set default parameters: ");
                EVP_PKEY_CTX_free(pctx);
                return nullptr;
            }
        } else {
            exception = _SecurityException_("Cannot allocate EVP parameters");
            return nullptr;
        }
    } else if (type == EVP_PKEY_DH) {
        params = EVP_PKEY_new();
        if (params != nullptr) {
            DH* dh = DH_get_2048_256();
            if (dh != nullptr) {
#if IS_OPENSSL_1_1_1d
                int dh_type = DH_get0_q(dh) == NULL ? EVP_PKEY_DH : EVP_PKEY_DHX;
                if (EVP_PKEY_assign(params, dh_type, dh) <= 0) {
#else
                if (EVP_PKEY_assign_DH(params, dh) <= 0) {
#endif  // if IS_OPENSSL_1_1_1d
                    exception = _SecurityException_("Cannot set default parameters: ");
                    DH_free(dh);
                    EVP_PKEY_free(params);
                    return nullptr;
                }
            }
        } else {
            exception = _SecurityException_("Cannot allocate EVP parameters");
            return nullptr;
        }
    } else {
        exception = _SecurityException_("Wrong DH kind");
        return nullptr;
    }

    EVP_PKEY* keys = nullptr;
    EVP_PKEY_CTX* kctx = EVP_PKEY_CTX_new(params, NULL);

    if (kctx != nullptr) {
        if (1 == EVP_PKEY_keygen_init(kctx)) {
            if (1 != EVP_PKEY_keygen(kctx, &keys)) {
                exception = _SecurityException_("Cannot generate EVP key");
            }
        } else {
            exception = _SecurityException_("Cannot init EVP key");
        }

        EVP_PKEY_CTX_free(kctx);
    } else {
        exception = _SecurityException_("Cannot create EVP context");
    }

    ERR_clear_error();
    EVP_PKEY_free(params);
    if (pctx != nullptr) {
        EVP_PKEY_CTX_free(pctx);
    }
    return keys;
}

static bool store_dh_public_key(EVP_PKEY* dhkey, int type, std::vector<uint8_t>& buffer, SecurityException& exception) {
    bool returnedValue = false;

    if (type == EVP_PKEY_DH) {
        const DH* dh =
#if IS_OPENSSL_1_1
            EVP_PKEY_get0_DH(dhkey);
#else
            dhkey->pkey.dh;
#endif  // if IS_OPENSSL_1_1

        if (dh != nullptr) {
#if IS_OPENSSL_1_1
            const BIGNUM* pub_key = nullptr;
            const BIGNUM* priv_key = nullptr;
            DH_get0_key(dh, &pub_key, &priv_key);

#else
            const BIGNUM* pub_key = dh->pub_key;
#endif  // if IS_OPENSSL_1_1

            int len = BN_num_bytes(pub_key);
            buffer.resize(len);
            unsigned char* pointer = buffer.data();
            if (BN_bn2bin(pub_key, pointer) == len) {
                returnedValue = true;
            } else {
                exception = _SecurityException_("Cannot serialize public key");
            }
        } else {
            exception = _SecurityException_("OpenSSL library doesn't retrieve DH");
        }
    } else if (type == EVP_PKEY_EC) {
        const EC_KEY* ec =
#if IS_OPENSSL_1_1
            EVP_PKEY_get0_EC_KEY(dhkey);
#else
            dhkey->pkey.ec;
#endif  // if IS_OPENSSL_1_1
        if (ec != nullptr) {
            auto grp = EC_KEY_get0_group(ec);
            auto pub_key = EC_KEY_get0_public_key(ec);
            auto len = EC_POINT_point2oct(grp, pub_key, EC_KEY_get_conv_form(ec), NULL, 0, NULL);
            buffer.resize(len);
            if (EC_POINT_point2oct(grp, pub_key, EC_KEY_get_conv_form(ec), buffer.data(), len, NULL) == len) {
                returnedValue = true;
            } else {
                exception = _SecurityException_("Cannot serialize public key");
            }
        } else {
            exception = _SecurityException_("OpenSSL library doesn't retrieve DH");
        }
    } else {
        exception = _SecurityException_("Wrong DH kind");
    }

    return returnedValue;
}

static EVP_PKEY* generate_dh_peer_key(const std::vector<uint8_t>& buffer, SecurityException& exception, int alg_kind) {
    if (alg_kind == EVP_PKEY_DH) {
        DH* dh = DH_get_2048_256();

        if (dh != nullptr) {
            const unsigned char* pointer = buffer.data();

#if IS_OPENSSL_1_1
            BIGNUM* pub_key_ptr;
            BIGNUM** pub_key = &pub_key_ptr;
#else
            BIGNUM** pub_key = &dh->pub_key;
#endif  // if IS_OPENSSL_1_1

            if ((pointer = BN_deserialize_raw(pub_key, buffer.data(), buffer.size(), exception)) != nullptr) {
#if IS_OPENSSL_1_1
                if (!DH_set0_key(dh, *pub_key, NULL))
                    return nullptr;
#endif  // if IS_OPENSSL_1_1
                EVP_PKEY* key = EVP_PKEY_new();

                if (key != nullptr) {
#if IS_OPENSSL_1_1_1d
                    int type = DH_get0_q(dh) == NULL ? EVP_PKEY_DH : EVP_PKEY_DHX;
                    if (EVP_PKEY_assign(key, type, dh) > 0)
#else
                    if (EVP_PKEY_assign_DH(key, dh) > 0)
#endif  // if IS_OPENSSL_1_1_1d
                    {
                        return key;
                    } else {  // LCOV_EXCL_START
                        exception = _SecurityException_("OpenSSL library cannot set dh in pkey");
                        DH_free(dh);
                    }

                    EVP_PKEY_free(key);
                } else {
                    exception = _SecurityException_("OpenSSL library cannot create pkey");
                }
            } else {
                exception = _SecurityException_("Cannot deserialize public key");
            }
        } else {
            exception = _SecurityException_("OpenSSL library cannot create dh");
        }  // LCOV_EXCL_STOP
    } else if (alg_kind == EVP_PKEY_EC) {
        EC_KEY* ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);

        if (ec != nullptr) {
            const unsigned char* pointer = buffer.data();

#if IS_OPENSSL_1_1
            if (EC_KEY_oct2key(ec, pointer, buffer.size(), NULL) > 0)
#else
            if (o2i_ECPublicKey(&ec, &pointer, (long)buffer.size()) != nullptr)
#endif  // if IS_OPENSSL_1_1
            {
                EVP_PKEY* key = EVP_PKEY_new();

                if (key != nullptr) {
                    if (EVP_PKEY_assign_EC_KEY(key, ec) > 0) {
                        return key;
                    } else {  // LCOV_EXCL_START
                        exception = _SecurityException_("OpenSSL library cannot set ec in pkey");
                    }

                    EVP_PKEY_free(key);
                } else {
                    exception = _SecurityException_("OpenSSL library cannot create pkey");
                }
            } else {
                exception = _SecurityException_("Cannot deserialize public key");
            }

            EC_KEY_free(ec);
        } else {
            exception = _SecurityException_("OpenSSL library cannot create ec");
        }
    } else {
        exception = _SecurityException_("Wrong DH kind");
    }  // LCOV_EXCL_STOP

    return nullptr;
}

static bool generate_challenge(std::vector<uint8_t>& vector, SecurityException& exception) {
    bool returnedValue = false;
    BIGNUM* bn = BN_new();

    if (BN_rand(bn, 256, 0 /*BN_RAND_TOP_ONE*/, 0 /*BN_RAND_BOTTOM_ANY*/)) {
        int len = BN_num_bytes(bn);
        vector.resize(len);

        if (BN_bn2bin(bn, vector.data()) == len) {
            returnedValue = true;
        } else {
            exception = _SecurityException_("OpenSSL library cannot store challenge");
        }
    }

    BN_clear_free(bn);

    return returnedValue;
}

std::shared_ptr<SecretHandle> PKIDH::generate_sharedsecret(EVP_PKEY* private_key, EVP_PKEY* public_key,
                                                           SecurityException& exception) const {
    assert(private_key);
    assert(public_key);

    std::shared_ptr<SharedSecretHandle> handle;
    EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(private_key, NULL);

    if (ctx != nullptr) {
        if (EVP_PKEY_derive_init(ctx) > 0) {
            if (EVP_PKEY_derive_set_peer(ctx, public_key) > 0) {
                size_t length = 0;
                if (EVP_PKEY_derive(ctx, NULL, &length) > 0) {
                    SharedSecret::BinaryData data;
                    data.name("SharedSecret");
                    data.value().resize(length);

                    if (EVP_PKEY_derive(ctx, data.value().data(), &length) > 0) {
                        uint8_t md[32];
                        if (EVP_Digest(data.value().data(), length, md, NULL, EVP_sha256(), NULL)) {
                            data.value().assign(md, md + 32);
                            handle = std::dynamic_pointer_cast<SharedSecretHandle>(
                                get_shared_secret(SharedSecretHandle::nil_handle, exception));
                            (*handle)->data_.push_back(std::move(data));
                        } else {  // LCOV_EXCL_START
                            exception = _SecurityException_("OpenSSL library failed while getting derived key");
                        }
                    } else {
                        exception = _SecurityException_("OpenSSL library cannot get derive");
                    }
                } else {
                    exception = _SecurityException_("OpenSSL library cannot get length");
                }
            } else {
                exception = _SecurityException_("OpenSSL library cannot set peer");
            }
        } else {
            exception = _SecurityException_("OpenSSL library cannot init derive");
        }

        EVP_PKEY_CTX_free(ctx);
    } else {
        exception = _SecurityException_("OpenSSL library cannot allocate context");
    }  // LCOV_EXCL_STOP

    return std::dynamic_pointer_cast<SecretHandle>(handle);
}

std::shared_ptr<SecretHandle> PKIDH::generate_sharedsecret_mvbs() {
    /*The m core does not actually have this part of the interface.
    This function is added so that sharedsecret is not NULL and a random sharedsecret is generated*/
    SecurityException exception;
    std::shared_ptr<SharedSecretHandle> handle;
    handle =
        std::dynamic_pointer_cast<SharedSecretHandle>(get_shared_secret(SharedSecretHandle::nil_handle, exception));

    std::vector<uint8_t> dummy_data, challenge_1, challenge_2;
    SharedSecret::BinaryData binary_data;
    challenge_1.resize(32);
    challenge_2.resize(32);

    RAND_bytes(challenge_1.data(), 32);
    binary_data.name("Challenge1");
    binary_data.value(challenge_1);
    (*handle)->data_.push_back(binary_data);

    RAND_bytes(challenge_2.data(), 32);
    binary_data.name("Challenge2");
    binary_data.value(challenge_2);
    (*handle)->data_.push_back(binary_data);

    dummy_data.resize(32);
    RAND_bytes(dummy_data.data(), 32);
    binary_data.name("SharedSecret");
    binary_data.value(dummy_data);
    (*handle)->data_.push_back(binary_data);

    (*handle)->data_.push_back(std::move(binary_data));

    return std::dynamic_pointer_cast<SecretHandle>(handle);
}

static bool generate_identity_token(PKIIdentityHandle& handle) {
    Property property;
    IdentityToken& token = handle->identity_token_;
    token.class_id("DDS:Auth:PKI-DH:1.0");

    property.name("dds.cert.sn");
    property.value() = handle->cert_sn_;
    property.propagate(true);
    token.properties().push_back(std::move(property));

    property.name("dds.cert.algo");
    property.value() = handle->sign_alg_;
    property.propagate(true);
    token.properties().push_back(std::move(property));

    property.name("dds.ca.sn");
    property.value() = handle->sn;
    property.propagate(true);
    token.properties().push_back(std::move(property));

    property.name("dds.ca.algo");
    property.value() = handle->algo;
    property.propagate(true);
    token.properties().push_back(std::move(property));

    property.name("dds.mvbs.cert.algo");
    property.value() = handle->mvbs_sign_alg_;
    property.propagate(true);
    token.properties().push_back(std::move(property));

    // property.name("dds.mvbs_sec.valid");
    // property.value() = "OFF";
    // property.propagate(true);
    // token.properties().push_back(std::move(property));

    return true;
}

ValidationResult_t PKIDH::validate_local_identity(IdentityHandle** local_identity_handle,
                                                  GUID_t& adjusted_participant_key, const uint32_t /*domain_id*/,
                                                  const RTPSParticipantAttributes& participant_attr,
                                                  const GUID_t& candidate_participant_key,
                                                  SecurityException& exception) {
    assert(local_identity_handle);

#if VBSAUTH
    /*vbsauth 初始值为不启动*/
    is_use_vbsauth = false;
#endif

    PropertyPolicy auth_properties =
        PropertyPolicyHelper::get_properties_with_prefix(participant_attr.properties, "dds.sec.auth.builtin.PKI-DH.");

    if (PropertyPolicyHelper::length(auth_properties) == 0) {
        exception = _SecurityException_("Not found any dds.sec.auth.builtin.PKI-DH property");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    std::string* identity_ca = PropertyPolicyHelper::find_property(auth_properties, "identity_ca");

    if (identity_ca == nullptr) {
        exception = _SecurityException_("Not found dds.sec.auth.builtin.PKI-DH.identity_ca property");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    std::string* identity_cert = PropertyPolicyHelper::find_property(auth_properties, "identity_certificate");

    if (identity_cert == nullptr) {
        exception = _SecurityException_("Not found dds.sec.auth.builtin.PKI-DH.identity_certificate property");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    std::string* identity_crl = PropertyPolicyHelper::find_property(auth_properties, "identity_crl");

    std::string* private_key = PropertyPolicyHelper::find_property(auth_properties, "private_key");

    if (private_key == nullptr) {
        exception = _SecurityException_("Not found dds.sec.auth.builtin.PKI-DH.private_key property");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

#if VBSAUTH
    if (((*private_key).size() >= 12) && ((*private_key).compare(0, 12, "liddsauth://") == 0)) {
        std::string key_path = (*private_key).substr(12);
        int ret = vbsauth.init();

        if (ret != VBSAuthErrorCode::NONE_ERROR) {
            is_use_vbsauth = false;
            exception = _SecurityException_(std::string("VBSAUTH init failed,error num ") + std::to_string(ret) +
                                            std::string(" private key path:") + key_path);
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
            return ValidationResult_t::VALIDATION_FAILED;
        } else {
            is_use_vbsauth = true;
        }
    }
#endif

    std::string* password = PropertyPolicyHelper::find_property(auth_properties, "password");
    std::string empty_password;

    if (password == nullptr) {
        password = &empty_password;
    }

    /*kagree_alg*/
    std::string* kagree_alg = PropertyPolicyHelper::find_property(auth_properties, "kagree_alg");
    std::string* mvbs_sign_alg = PropertyPolicyHelper::find_property(auth_properties, "mvbs_sign_alg");
    PKIIdentityHandle* ih = &PKIIdentityHandle::narrow(*get_identity_handle(exception));

    if (mvbs_sign_alg == nullptr) {
        (*ih)->mvbs_sign_alg_ = "MVBS_SIMPLE";
    } else {
        (*ih)->mvbs_sign_alg_ = *mvbs_sign_alg;
    }

    if ((*ih)->mvbs_sign_alg_.compare("ED25519") == 0) {
        // mcore ed25519 priv_key pub_key
        std::string* ed25519_private_pkey =
            PropertyPolicyHelper::find_property(auth_properties, "ed25519_private_pkey");
        if (ed25519_private_pkey == nullptr) {
            exception = _SecurityException_("Not found dds.sec.auth.builtin.PKI-DH.ed25519_private_pkey property");
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
            delete ih;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        std::string* ed25519_public_pkey = PropertyPolicyHelper::find_property(auth_properties, "ed25519_public_pkey");
        if (ed25519_public_pkey == nullptr) {
            exception = _SecurityException_("Not found dds.sec.auth.builtin.PKI-DH.ed25519_public_pkey property");
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
            delete ih;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        (*ih)->ed25519_local_private_pkey_ = load_ed25519_privatekey(*ed25519_private_pkey);
        if ((*ih)->ed25519_local_private_pkey_ == NULL) {
            EMERGENCY_SECURITY_LOGGING("PKIDH", "load ed25519_privatekey failed");
            delete ih;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        (*ih)->ed25519_local_public_pkey_ = load_ed25519_publickey(*ed25519_public_pkey);
        if ((*ih)->ed25519_local_public_pkey_ == NULL) {
            EMERGENCY_SECURITY_LOGGING("PKIDH", "load ed25519_public_pkey failed");
            delete ih;
            return ValidationResult_t::VALIDATION_FAILED;
        }
    } else if ((*ih)->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0) {
        std::string* hmac_key = PropertyPolicyHelper::find_property(auth_properties, "mvbs_hmac_key");

        if (hmac_key == nullptr) {
            for (unsigned char i = 1; i <= 32; ++i) {
                (*ih)->mhmac_key.push_back(i);
            }
        } else {
            if (!load_mvbs_hmac_key(*hmac_key, (*ih)->mhmac_key)) {
                exception = _SecurityException_("dds.sec.auth.builtin.PKI-DH.mvbs_hmac_key file read failed");
                DEBUG_SECURITY_LOGGING("PKIDH", exception.what());
            }
        }

    } else {
        EMERGENCY_SECURITY_LOGGING("PKIDH", "unknow mvbs_sign_alg");
        delete ih;
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (kagree_alg == nullptr) {
        (*ih)->kagree_alg_ = "DH+MODP-2048-256";
    } else {
        if ((*ih)->kagree_alg_.compare("DH+MODP-2048-256") && (*ih)->kagree_alg_.compare("ECDH+prime256v1-CEUM")) {
            (*ih)->kagree_alg_ = "DH+MODP-2048-256";
            std::cout << "use default kagree_alg:" << (*ih)->kagree_alg_.c_str() << std::endl;
        }
        (*ih)->kagree_alg_ = *kagree_alg;
    }
    //   std::cout<<"kagree_alg:"<<(*ih)->kagree_alg_.c_str()<<std::endl;

    (*ih)->store_ = load_identity_ca(*identity_ca, (*ih)->there_are_crls_, (*ih)->sn, (*ih)->algo, exception);

    if ((*ih)->store_ != nullptr) {
        ERR_clear_error();

        if (identity_crl != nullptr) {
            X509_CRL* crl = load_crl(*identity_crl, exception);

            if (crl != nullptr) {
                (void)X509_STORE_add_crl((*ih)->store_, crl);
                X509_CRL_free(crl);
                (*ih)->there_are_crls_ = true;
            } else {
                delete ih;
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        ERR_clear_error();

        (*ih)->cert_ = load_certificate(*identity_cert, &(*ih)->intermediate_certs_, exception);

        if ((*ih)->cert_ != nullptr) {
            // Get subject name.
            X509_NAME* cert_sn = X509_get_subject_name((*ih)->cert_);
            assert(cert_sn != nullptr);
            char* cert_sn_str = X509_NAME_oneline(cert_sn, 0, 0);
            assert(cert_sn_str != nullptr);
            (*ih)->cert_sn_ = cert_sn_str;
            OPENSSL_free(cert_sn_str);
            BIO* cert_sn_rfc2253_str = BIO_new(BIO_s_mem());
            (void)X509_NAME_print_ex(cert_sn_rfc2253_str, cert_sn, 0, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
            const int bufsize = 1024;
            char buffer[1024];
            int length = BIO_read(cert_sn_rfc2253_str, buffer, bufsize);
            (void)BIO_free(cert_sn_rfc2253_str);
            if (length >= 0) {
                (void)(*ih)->cert_sn_rfc2253_.assign(buffer, length);

                if (
#if VBSAUTH
                    is_use_vbsauth ||
#endif
                    verify_certificate((*ih)->store_, (*ih)->cert_, (*ih)->there_are_crls_, (*ih)->intermediate_certs_,
                                       exception)) {
                    if (store_certificate_in_buffer((*ih)->cert_, (*ih)->intermediate_certs_, &(*ih)->cert_content_,
                                                    exception)) {
                        if (get_signature_algorithm((*ih)->cert_, (*ih)->sign_alg_, exception)) {
                            (*ih)->pkey_ = load_private_key((*ih)->cert_, *private_key, *password, exception, *this);

                            if ((*ih)->pkey_ != nullptr
#if VBSAUTH
                                || is_use_vbsauth == true
#endif
                            ) {
                                if (adjust_participant_key((*ih)->cert_, candidate_participant_key,
                                                           adjusted_participant_key, exception)) {
                                    // Generate IdentityToken.
                                    if (generate_identity_token(*ih)) {
                                        (*ih)->participant_key_ = adjusted_participant_key;
                                        *local_identity_handle = ih;
                                        NOTICE_SECURITY_LOGGING("PKIDH", "local verify success!");
                                        return ValidationResult_t::VALIDATION_OK;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());

    delete ih;

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::validate_remote_identity(IdentityHandle** remote_identity_handle,
                                                   const IdentityHandle& local_identity_handle,
                                                   const IdentityToken& remote_identity_token,
                                                   const GUID_t& remote_participant_key, SecurityException& exception) {
    assert(remote_identity_handle);
    assert(local_identity_handle.nil() == false);

    ValidationResult_t returnedValue = ValidationResult_t::VALIDATION_FAILED;

    const PKIIdentityHandle& lih = PKIIdentityHandle::narrow(local_identity_handle);

    if ((!lih.nil()) && (!remote_identity_token.is_nil())) {
        // dds.mvbs.cert.algo
        const std::string* mvbs_cert_algo =
            DataHolderHelper::find_property_value(remote_identity_token, "dds.mvbs.cert.algo");

        // dds.mvbs.cert.algo
        const std::string* mvbs_valid =
            DataHolderHelper::find_property_value(remote_identity_token, "dds.mvbs_sec.valid");

        // dds.ca.sn
        const std::string* ca_sn = DataHolderHelper::find_property_value(remote_identity_token, "dds.ca.sn");

        // dds.cert.sn
        // const std::string* cert_sn = DataHolderHelper::find_property_value(remote_identity_token,
        // "dds.cert.sn");

        // dds.cert.algo
        const std::string* cert_algo = DataHolderHelper::find_property_value(remote_identity_token, "dds.cert.algo");

        PKIIdentityHandle* rih = &PKIIdentityHandle::narrow(*get_identity_handle(exception));

        bool is_mvbs_ = (mvbs_valid && *mvbs_valid == "ON");

        if (is_mvbs_ && mvbs_cert_algo) {
            if (*mvbs_cert_algo == lih->mvbs_sign_alg_) {
                (*rih)->mvbs_sign_alg_ = *mvbs_cert_algo;
                (*rih)->ismvbs_sec = true;
            } else {
                exception = _SecurityException_("Bad remote mvbs cert alg local:" + lih->mvbs_sign_alg_ +
                                                " remote:" + *mvbs_cert_algo);
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                return returnedValue;
            }
        }

        (*rih)->sn = ca_sn ? *ca_sn : "";
        (*rih)->cert_sn_ = "";  // cert_sn ? *cert_sn : "";
        (*rih)->algo = cert_algo ? *cert_algo : "";
        (*rih)->participant_key_ = remote_participant_key;
        *remote_identity_handle = rih;

        if (lih->participant_key_ < remote_participant_key) {
            // if (remote_participant_key < lih->participant_key_) {
            returnedValue = ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST;
        } else {
            returnedValue = ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
        }

        // delete rih;
    }

    return returnedValue;
}

ValidationResult_t PKIDH::begin_handshake_request(HandshakeHandle** handshake_handle,
                                                  HandshakeMessageToken** handshake_message,
                                                  const IdentityHandle& initiator_identity_handle,
                                                  IdentityHandle& replier_identity_handle,
                                                  const CDRMessage_t& cdr_participant_data,
                                                  SecurityException& exception) {
    assert(handshake_handle);
    assert(handshake_message);
    assert(initiator_identity_handle.nil() == false);
    assert(replier_identity_handle.nil() == false);

    const PKIIdentityHandle& lih = PKIIdentityHandle::narrow(initiator_identity_handle);
    PKIIdentityHandle& rih = PKIIdentityHandle::narrow(replier_identity_handle);

    if (lih.nil() || rih.nil()) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (cdr_participant_data.length == 0) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    unsigned char md[SHA256_DIGEST_LENGTH];

    // New handshake
    PKIHandshakeHandle* handshake_handle_aux = new PKIHandshakeHandle();
    if (!rih->ismvbs_sec) {
        (*handshake_handle_aux)->kagree_alg_ = lih->kagree_alg_;
        (*handshake_handle_aux)->handshake_message_.class_id("DDS:Auth:PKI-DH:1.0+Req");

        BinaryProperty bproperty;

        // c.id
        bproperty.name("c.id");
        bproperty.value().assign(lih->cert_content_->data, lih->cert_content_->data + lih->cert_content_->length);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // c.perm
        if (lih->permissions_credential_token_.class_id().compare("DDS:Access:PermissionsCredential") == 0) {
            const Property* permissions_file =
                DataHolderHelper::find_property(lih->permissions_credential_token_, "dds.perm.cert");

            if (permissions_file != nullptr) {
                bproperty.name("c.perm");
                bproperty.value().assign(permissions_file->value().begin(), permissions_file->value().end());
                bproperty.propagate(true);
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));
            } else {
                exception = _SecurityException_("Cannot find permissions file in permissions credential token");
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                delete handshake_handle_aux;
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        // c.pdata
        bproperty.name("c.pdata");
        bproperty.value().assign(cdr_participant_data.buffer,
                                 cdr_participant_data.buffer + cdr_participant_data.length);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // c.dsign_algo.
        bproperty.name("c.dsign_algo");
        bproperty.value().assign(lih->sign_alg_.begin(), lih->sign_alg_.end());
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // TODO(Ricardo) Only support right now DH+MODP-2048-256
        // c.kagree_algo.
        bproperty.name("c.kagree_algo");
        bproperty.value().assign(lih->kagree_alg_.begin(), lih->kagree_alg_.end());
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));
        // std::cout<<"kagree_alg_1:"<<lih->kagree_alg_.c_str()<<std::endl;

        // hash_c1
        CDRMessage_t message(static_cast<uint32_t>(
            BinaryPropertyHelper::serialized_size((*handshake_handle_aux)->handshake_message_.binary_properties())));
        message.msg_endian = BIGEND;
        (void)CDRMessage::addBinaryPropertySeq(&message,
                                               (*handshake_handle_aux)->handshake_message_.binary_properties(), false);
        if (!EVP_Digest(message.buffer, message.length, md, NULL, EVP_sha256(), NULL)) {
            exception = _SecurityException_("OpenSSL library cannot hash sha256");
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
            delete handshake_handle_aux;
            return ValidationResult_t::VALIDATION_FAILED;
        }
        bproperty.name("hash_c1");
        bproperty.value().assign(md, md + SHA256_DIGEST_LENGTH);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        int kagree_kind = get_dh_type((*handshake_handle_aux)->kagree_alg_);

        // dh1
        if (((*handshake_handle_aux)->dhkeys_ = generate_dh_key(kagree_kind, exception)) != nullptr) {
            bproperty.name("dh1");
            bproperty.propagate(true);

            if (store_dh_public_key((*handshake_handle_aux)->dhkeys_, kagree_kind, bproperty.value(), exception)) {
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                // challenge1
                bproperty.name("challenge1");
                bproperty.propagate(true);
                if (generate_challenge(bproperty.value(), exception)) {
                    (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                    (*handshake_handle_aux)->local_identity_handle_ = &lih;
                    (*handshake_handle_aux)->remote_identity_handle_ = &rih;
                    *handshake_handle = handshake_handle_aux;
                    *handshake_message = &(*handshake_handle_aux)->handshake_message_;
                    return ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
                }
            }
        }
    } else {
        (*handshake_handle_aux)->handshake_message_.class_id("DDS:Auth:MVBS+Req");

        BinaryProperty bproperty;

        // dds msg:Q1
        rih->msec_q.resize(MVBS_SEC_Q_LEN);
        RAND_bytes(rih->msec_q.data(), MVBS_SEC_Q_LEN);

        bproperty.name("dds.msg");
        bproperty.value().assign(rih->msec_q.data(), rih->msec_q.data() + MVBS_SEC_Q_LEN);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0 || (lih->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0)) {
            // pub
            std::vector<uint8_t> pkeytouint8;
            if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
                if (!coverPemtovector_base64(lih->ed25519_local_public_pkey_, pkeytouint8, exception)) {
                    EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                    delete handshake_handle_aux;
                    return ValidationResult_t::VALIDATION_FAILED;
                }
            } else {
                pkeytouint8.resize(PUBKEY_SIZE);
                std::fill(pkeytouint8.begin(), pkeytouint8.end(), 0);
            }

            bproperty.name("dds.pub");
            bproperty.value().assign(pkeytouint8.data(), pkeytouint8.data() + pkeytouint8.size());
            bproperty.propagate(true);
            (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));
        } else {
            EMERGENCY_SECURITY_LOGGING("PKIDH", "no find mvbs sign alg");
            delete handshake_handle_aux;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        DEBUG_SECURITY_LOGGING("PKIDH", std::string("send mvbs req"));
        (*handshake_handle_aux)->local_identity_handle_ = &lih;
        (*handshake_handle_aux)->remote_identity_handle_ = &rih;
        *handshake_handle = handshake_handle_aux;
        *handshake_message = &(*handshake_handle_aux)->handshake_message_;
        return ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
    }
    delete handshake_handle_aux;

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::begin_handshake_reply(HandshakeHandle** handshake_handle,
                                                HandshakeMessageToken** handshake_message_out,
                                                HandshakeMessageToken&& handshake_message_in,
                                                IdentityHandle& initiator_identity_handle,
                                                const IdentityHandle& replier_identity_handle,
                                                const CDRMessage_t& cdr_participant_data,
                                                SecurityException& exception) {
    assert(handshake_handle);
    assert(handshake_message_out);
    assert(initiator_identity_handle.nil() == false);
    assert(replier_identity_handle.nil() == false);

    const PKIIdentityHandle& lih = PKIIdentityHandle::narrow(replier_identity_handle);
    PKIIdentityHandle& rih = PKIIdentityHandle::narrow(initiator_identity_handle);

    if (lih.nil() || rih.nil()) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (cdr_participant_data.length == 0) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (!rih->ismvbs_sec) {
        // Check TokenMessage
        if (handshake_message_in.class_id().compare("DDS:Auth:PKI-DH:1.0+Req") != 0) {
            WARNING_SECURITY_LOGGING(
                "PKIDH", std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // Check incoming handshake.
        // Check c.id
        const std::vector<uint8_t>* cid = DataHolderHelper::find_binary_property_value(handshake_message_in, "c.id");
        if (cid == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.id");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        //! Release the memory in case of having an old certificate
        if (rih->cert_ != nullptr) {
            X509_free(rih->cert_);
            rih->cert_ = nullptr;
        }
        if (rih->intermediate_certs_ != nullptr) {
            sk_X509_pop_free(rih->intermediate_certs_, X509_free);
            rih->intermediate_certs_ = nullptr;
        }

        rih->cert_ = load_certificate(*cid, &rih->intermediate_certs_);

        if (rih->cert_ == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot load certificate");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        X509_NAME* cert_sn = X509_get_subject_name(rih->cert_);
        assert(cert_sn != nullptr);
        char* cert_sn_str = X509_NAME_oneline(cert_sn, 0, 0);
        assert(cert_sn_str != nullptr);
        if ((!rih->cert_sn_.empty()) && (rih->cert_sn_.compare(cert_sn_str) != 0)) {
            OPENSSL_free(cert_sn_str);
            WARNING_SECURITY_LOGGING("PKIDH", "Certificated subject name invalid");
            return ValidationResult_t::VALIDATION_FAILED;
        }
        (void)rih->cert_sn_.assign(cert_sn_str);
        OPENSSL_free(cert_sn_str);
        BIO* cert_sn_rfc2253_str = BIO_new(BIO_s_mem());
        (void)X509_NAME_print_ex(cert_sn_rfc2253_str, cert_sn, 0, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
        const int bufsize = 1024;
        char buffer[1024];
        int str_length = BIO_read(cert_sn_rfc2253_str, buffer, bufsize);
        (void)BIO_free(cert_sn_rfc2253_str);
        if (str_length < 0) {
            WARNING_SECURITY_LOGGING("PKIDH", "Error cert_sn_rfc2253 length");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        (void)rih->cert_sn_rfc2253_.assign(buffer, str_length);
        if (!verify_certificate(lih->store_, rih->cert_, lih->there_are_crls_, rih->intermediate_certs_, exception)) {
            WARNING_SECURITY_LOGGING("PKIDH", std::string("Error verifying certificate:") + exception.what());
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // c.perm
        if (lih->permissions_credential_token_.class_id().compare("DDS:Access:PermissionsCredential") == 0) {
            const std::vector<uint8_t>* perm =
                DataHolderHelper::find_binary_property_value(handshake_message_in, "c.perm");

            if (perm == nullptr) {
                WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.perm");
                return ValidationResult_t::VALIDATION_FAILED;
            }

            rih->permissions_credential_token_.class_id("DDS:Access:PermissionsCredential");
            Property permission_file;
            permission_file.name("dds.perm.cert");
            (void)permission_file.value().assign(perm->begin(), perm->end());
            rih->permissions_credential_token_.properties().push_back(std::move(permission_file));
        }

        const std::vector<uint8_t>* pdata =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "c.pdata");

        if (pdata == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.pdata");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        GUID_t participant_guid;
        CDRMessage_t cdr_pdata(0);
        cdr_pdata.wraps = true;
        cdr_pdata.msg_endian = BIGEND;
        cdr_pdata.length = (uint32_t)pdata->size();
        cdr_pdata.max_size = (uint32_t)pdata->size();
        cdr_pdata.buffer = (octet*)pdata->data();

        if (!ParameterList::read_guid_from_cdr_msg(cdr_pdata, edds::dds::PID_PARTICIPANT_GUID, participant_guid)) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot deserialize ParticipantProxyData in property c.pdata");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        if ((participant_guid.guidPrefix.value[8] & 0x80) != 0x80) {
            DEBUG_SECURITY_LOGGING("PKIDH", "Bad participant_key's first bit in c.pdata");
            // return ValidationResult_t::VALIDATION_FAILED;
        }

        unsigned char md[SHA256_DIGEST_LENGTH];
        unsigned char hash_c1[SHA256_DIGEST_LENGTH];
        uint32_t length = 0;

        if ((!X509_NAME_digest(cert_sn, EVP_sha256(), md, &length)) || (length != SHA256_DIGEST_LENGTH)) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot generate SHA256 of subject name");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        unsigned char bytes[4] {static_cast<unsigned char>((participant_guid.guidPrefix.value[8] << 1) |
                                                           (participant_guid.guidPrefix.value[9] >> 7)),
                                static_cast<unsigned char>((participant_guid.guidPrefix.value[9] << 1) |
                                                           (participant_guid.guidPrefix.value[10] >> 7)),
                                static_cast<unsigned char>((participant_guid.guidPrefix.value[10] << 1) |
                                                           (participant_guid.guidPrefix.value[11] >> 7)),
                                static_cast<unsigned char>(participant_guid.guidPrefix.value[11] << 1)};
        md[sizeof(bytes) - 1] &= 0xFE;

        if (memcmp(md, bytes, sizeof(bytes)) != 0) {
            DEBUG_SECURITY_LOGGING("PKIDH", "Bad participant_key's 47bits in c.pdata");
            // return ValidationResult_t::VALIDATION_FAILED;
        }

        // c.dsign_algo
        const std::vector<uint8_t>* dsign_algo =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "c.dsign_algo");

        if (dsign_algo == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.dsign_algo");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // Check signature algorithm
        std::string s_dsign_algo(dsign_algo->begin(), dsign_algo->end());
        if ((strcmp(evbs::ertps::rtps::security::RSA_SHA256, s_dsign_algo.c_str()) != 0) &&
            (strcmp(evbs::ertps::rtps::security::ECDSA_SHA256, s_dsign_algo.c_str()) != 0) &&
            (strcmp(evbs::ertps::rtps::security::ECDSA_SHA384, s_dsign_algo.c_str()) != 0)) {
            WARNING_SECURITY_LOGGING("PKIDH", "Not supported signature algorithm (" + s_dsign_algo + ")");
            return ValidationResult_t::VALIDATION_FAILED;
        }
        rih->sign_alg_ = std::move(s_dsign_algo);

        // std::cout<<"kagree_alg_1:"<<rih->kagree_alg_.c_str()<<std::endl;
        // c.kagree_algo
        const std::vector<uint8_t>* kagree_algo =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "c.kagree_algo");

        if (kagree_algo == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.kagree_algo");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // Check key agreement algorithm
        std::string s_kagree_algo(kagree_algo->begin(), kagree_algo->end());
        if (strcmp(evbs::ertps::rtps::security::DH_2048_256, s_kagree_algo.c_str()) != 0 &&
            strcmp(evbs::ertps::rtps::security::ECDH_prime256v1, s_kagree_algo.c_str()) != 0) {
            WARNING_SECURITY_LOGGING("PKIDH",
                                     std::string("Not supported key agreement algorithm (") + s_kagree_algo + ")");
            return ValidationResult_t::VALIDATION_FAILED;
        }
        rih->kagree_alg_ = std::move(s_kagree_algo);

        CDRMessage_t cdrmessage(
            static_cast<uint32_t>(BinaryPropertyHelper::serialized_size(handshake_message_in.binary_properties())));
        cdrmessage.msg_endian = BIGEND;
        (void)CDRMessage::addBinaryPropertySeq(&cdrmessage, handshake_message_in.binary_properties(), "c.", false);

        if (!EVP_Digest(cdrmessage.buffer, cdrmessage.length, hash_c1, NULL, EVP_sha256(), NULL)) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot generate SHA256 of request");
            return ValidationResult_t::VALIDATION_FAILED;
        } else {
            // hash_c1
            std::vector<uint8_t>* hash_c1_vec =
                DataHolderHelper::find_binary_property_value(handshake_message_in, "hash_c1");

            if (hash_c1_vec != nullptr) {
                if ((hash_c1_vec->size() == SHA256_DIGEST_LENGTH) &&
                    (memcmp(hash_c1, hash_c1_vec->data(), SHA256_DIGEST_LENGTH) != 0)) {
                    WARNING_SECURITY_LOGGING("PKIDH", "Wrong hash_c1");
                }
            }
        }

        // dh1
        std::vector<uint8_t>* dh1 = DataHolderHelper::find_binary_property_value(handshake_message_in, "dh1");

        if (dh1 == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dh1");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // challenge1
        std::vector<uint8_t>* challenge1 =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "challenge1");

        if (challenge1 == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property challenge1");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // Generate handshake reply message token.
        PKIHandshakeHandle* handshake_handle_aux = new PKIHandshakeHandle();
        (*handshake_handle_aux)->kagree_alg_ = rih->kagree_alg_;
        (*handshake_handle_aux)->handshake_message_.class_id("DDS:Auth:PKI-DH:1.0+Reply");

        int kagree_kind = get_dh_type((*handshake_handle_aux)->kagree_alg_);

        // Store dh1
        if (((*handshake_handle_aux)->peerkeys_ = generate_dh_peer_key(*dh1, exception, kagree_kind)) == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot store peer key from dh1");
            delete handshake_handle_aux;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        BinaryProperty bproperty;

        // c.id
        bproperty.name("c.id");
        bproperty.value().assign(lih->cert_content_->data, lih->cert_content_->data + lih->cert_content_->length);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // c.perm
        if (lih->permissions_credential_token_.class_id().compare("DDS:Access:PermissionsCredential") == 0) {
            const Property* permissions_file =
                DataHolderHelper::find_property(lih->permissions_credential_token_, "dds.perm.cert");

            if (permissions_file != nullptr) {
                bproperty.name("c.perm");
                bproperty.value().assign(permissions_file->value().begin(), permissions_file->value().end());
                bproperty.propagate(true);
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));
            } else {
                exception = _SecurityException_("Cannot find permissions file in permissions credential token");
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                delete handshake_handle_aux;
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        // c.pdata
        bproperty.name("c.pdata");
        bproperty.value().assign(cdr_participant_data.buffer,
                                 cdr_participant_data.buffer + cdr_participant_data.length);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // c.dsign_algo.
        bproperty.name("c.dsign_algo");
        bproperty.value().assign(lih->sign_alg_.begin(), lih->sign_alg_.end());
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // TODO(Ricardo) Only support right now DH+MODP-2048-256
        // c.kagree_algo.
        bproperty.name("c.kagree_algo");
        bproperty.value().assign((*handshake_handle_aux)->kagree_alg_.begin(),
                                 (*handshake_handle_aux)->kagree_alg_.end());
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // hash_c2
        CDRMessage_t message(static_cast<uint32_t>(
            BinaryPropertyHelper::serialized_size((*handshake_handle_aux)->handshake_message_.binary_properties())));
        message.msg_endian = BIGEND;
        (void)CDRMessage::addBinaryPropertySeq(&message,
                                               (*handshake_handle_aux)->handshake_message_.binary_properties(), false);
        if (!EVP_Digest(message.buffer, message.length, md, NULL, EVP_sha256(), NULL)) {
            exception = _SecurityException_("OpenSSL library cannot hash sha256");
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
            delete handshake_handle_aux;
            return ValidationResult_t::VALIDATION_FAILED;
        }
        bproperty.name("hash_c2");
        bproperty.value().assign(md, md + SHA256_DIGEST_LENGTH);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        // dh2
        if (((*handshake_handle_aux)->dhkeys_ = generate_dh_key(kagree_kind, exception)) != nullptr) {
            bproperty.name("dh2");
            bproperty.propagate(true);

            if (store_dh_public_key((*handshake_handle_aux)->dhkeys_, kagree_kind, bproperty.value(), exception)) {
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                // hash_c1
                bproperty.name("hash_c1");
                bproperty.value().assign(hash_c1, hash_c1 + SHA256_DIGEST_LENGTH);
                bproperty.propagate(true);
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                // dh1
                bproperty.name("dh1");
                bproperty.value(std::move(*dh1));
                bproperty.propagate(true);
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                // challenge1
                bproperty.name("challenge1");
                bproperty.value(std::move(*challenge1));
                bproperty.propagate(true);
                (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                // challenge2
                bproperty.name("challenge2");
                bproperty.propagate(true);
                if (generate_challenge(bproperty.value(), exception)) {
                    (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                    // signature
                    CDRMessage_t cdrmessage2(static_cast<uint32_t>(BinaryPropertyHelper::serialized_size(
                        (*handshake_handle_aux)->handshake_message_.binary_properties())));
                    cdrmessage2.msg_endian = BIGEND;
                    // add sequence length
                    (void)CDRMessage::addUInt32(&cdrmessage2, 6);
                    // add hash_c2
                    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                                        *DataHolderHelper::find_binary_property(
                                                            (*handshake_handle_aux)->handshake_message_, "hash_c2"));
                    // add challenge2
                    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                                        *DataHolderHelper::find_binary_property(
                                                            (*handshake_handle_aux)->handshake_message_, "challenge2"));
                    // add dh2
                    (void)CDRMessage::addBinaryProperty(
                        &cdrmessage2,
                        *DataHolderHelper::find_binary_property((*handshake_handle_aux)->handshake_message_, "dh2"));
                    // add challenge1
                    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                                        *DataHolderHelper::find_binary_property(
                                                            (*handshake_handle_aux)->handshake_message_, "challenge1"));
                    // add dh1
                    (void)CDRMessage::addBinaryProperty(
                        &cdrmessage2,
                        *DataHolderHelper::find_binary_property((*handshake_handle_aux)->handshake_message_, "dh1"));
                    // add hash_c1
                    (void)CDRMessage::addBinaryProperty(
                        &cdrmessage2,
                        *DataHolderHelper::find_binary_property((*handshake_handle_aux)->handshake_message_, "hash_c1"),
                        false);

                    bproperty.name("signature");
                    bproperty.propagate(true);
                    if (sign_sha256(lih->pkey_, cdrmessage2.buffer, cdrmessage2.length, bproperty.value(), exception,
                                    *this)) {
                        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

                        (*handshake_handle_aux)->local_identity_handle_ = &lih;
                        (*handshake_handle_aux)->remote_identity_handle_ = &rih;
                        *handshake_handle = handshake_handle_aux;
                        *handshake_message_out = &(*handshake_handle_aux)->handshake_message_;

                        return ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
                    }
                }
            }
        }
        delete handshake_handle_aux;
    } else {
        DEBUG_SECURITY_LOGGING("PKIDH", std::string("handle mvbs req"));

        // Check TokenMessage
        if (handshake_message_in.class_id().compare("DDS:Auth:MVBS+Req") != 0) {
            WARNING_SECURITY_LOGGING(
                "PKIDH", std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // deal req
        const std::vector<uint8_t>* remote_mvbs_q =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.msg");
        if (remote_mvbs_q == nullptr || remote_mvbs_q->size() != MVBS_SEC_Q_LEN) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds msg");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
            const std::vector<uint8_t>* remote_ed25519_pub =
                DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.pub");
            if (remote_ed25519_pub == nullptr) {
                WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds msg");
                return ValidationResult_t::VALIDATION_FAILED;
            }

            rih->ed25519_remote_public_pkey_ = coverVectortoPem_base64(*remote_ed25519_pub, exception);
            if (rih->ed25519_remote_public_pkey_ == NULL) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        const char* buffer = "emailAddreee=VBS@lixiang.com,CN=LiDDS_MVBS_2729,OU=LiVBS,O=LiAuto,ST=Beijing,C=CN";
        (void)rih->cert_sn_rfc2253_.assign(buffer, strlen(buffer));

        // Generate handshake reply message token.
        PKIHandshakeHandle* handshake_handle_aux = new PKIHandshakeHandle();
        (*handshake_handle_aux)->handshake_message_.class_id("DDS:Auth:MVBS+Reply");

        BinaryProperty bproperty;
        // dds msg:Q2
        rih->msec_q.resize(MVBS_SEC_Q_LEN);
        RAND_bytes(rih->msec_q.data(), MVBS_SEC_Q_LEN);

        bproperty.name("dds.msg");
        bproperty.value().assign(rih->msec_q.data(), rih->msec_q.data() + MVBS_SEC_Q_LEN);
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0 || (lih->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0)) {
            std::vector<uint8_t> pkeytouint8;
            std::vector<uint8_t> p2sign(MVBS_SEC_Q_LEN), sign_data;
            p2sign.assign(remote_mvbs_q->begin(), remote_mvbs_q->end());

            generate_secret_P(lih->participant_key_, rih->participant_key_, p2sign);

            if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
                if (!coverPemtovector_base64(lih->ed25519_local_public_pkey_, pkeytouint8, exception)) {
                    EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                    delete handshake_handle_aux;
                    return ValidationResult_t::VALIDATION_FAILED;
                }

                if (!ed25519_sign_message(lih->ed25519_local_private_pkey_, p2sign, sign_data, exception)) {
                    EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                    delete handshake_handle_aux;
                    return ValidationResult_t::VALIDATION_FAILED;
                }
            } else {
                pkeytouint8.resize(PUBKEY_SIZE);
                std::fill(pkeytouint8.begin(), pkeytouint8.end(), 0);

                if (!mvbs_hmac_message(lih->mhmac_key, p2sign, sign_data, exception)) {
                    EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                    delete handshake_handle_aux;
                    return ValidationResult_t::VALIDATION_FAILED;
                }
            }

            bproperty.name("dds.pub");
            bproperty.value().assign(pkeytouint8.data(), pkeytouint8.data() + pkeytouint8.size());
            bproperty.propagate(true);
            (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

            bproperty.name("dds.sign");
            bproperty.value().assign(sign_data.data(), sign_data.data() + sign_data.size());
            bproperty.propagate(true);
            (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));
        } else {
            EMERGENCY_SECURITY_LOGGING("PKIDH", "no find mvbs sign alg");
            delete handshake_handle_aux;
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // hash
        std::vector<uint8_t> hash(32, 0);
        bproperty.name("dds.hash");
        bproperty.value().assign(hash.data(), hash.data() + hash.size());
        bproperty.propagate(true);
        (*handshake_handle_aux)->handshake_message_.binary_properties().push_back(std::move(bproperty));

        (*handshake_handle_aux)->local_identity_handle_ = &lih;
        (*handshake_handle_aux)->remote_identity_handle_ = &rih;
        *handshake_handle = handshake_handle_aux;
        *handshake_message_out = &(*handshake_handle_aux)->handshake_message_;
        return ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::process_handshake(HandshakeMessageToken** handshake_message_out,
                                            HandshakeMessageToken&& handshake_message_in,
                                            HandshakeHandle& handshake_handle, SecurityException& exception) {
    ValidationResult_t returnedValue = ValidationResult_t::VALIDATION_FAILED;

    PKIHandshakeHandle& handshake = PKIHandshakeHandle::narrow(handshake_handle);

    if (!handshake.nil()) {
        if (handshake->handshake_message_.class_id().compare("DDS:Auth:PKI-DH:1.0+Req") == 0) {
            returnedValue =
                process_handshake_request(handshake_message_out, std::move(handshake_message_in), handshake, exception);
        } else if (handshake->handshake_message_.class_id().compare("DDS:Auth:PKI-DH:1.0+Reply") == 0) {
            returnedValue =
                process_handshake_reply(handshake_message_out, std::move(handshake_message_in), handshake, exception);
        } else if (handshake->handshake_message_.class_id().compare("DDS:Auth:MVBS+Req") == 0) {
            returnedValue = process_handshake_request_mvbs(handshake_message_out, std::move(handshake_message_in),
                                                           handshake, exception);
        } else if (handshake->handshake_message_.class_id().compare("DDS:Auth:MVBS+Reply") == 0) {
            returnedValue = process_handshake_reply_mvbs(handshake_message_out, std::move(handshake_message_in),
                                                         handshake, exception);
        } else {
            WARNING_SECURITY_LOGGING("PKIDH", std::string("Handshake message not supported (") +
                                                  handshake->handshake_message_.class_id() + ")");
        }
    }

    return returnedValue;
}

ValidationResult_t PKIDH::process_handshake_request(HandshakeMessageToken** handshake_message_out,
                                                    HandshakeMessageToken&& handshake_message_in,
                                                    PKIHandshakeHandle& handshake_handle,
                                                    SecurityException& exception) {
    const PKIIdentityHandle& lih = *handshake_handle->local_identity_handle_;
    PKIIdentityHandle& rih = *handshake_handle->remote_identity_handle_;

    // Check TokenMessage
    if (handshake_message_in.class_id().compare("DDS:Auth:PKI-DH:1.0+Reply") != 0) {
        WARNING_SECURITY_LOGGING("PKIDH",
                                 std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // Check incoming handshake.
    // Check c.id
    const std::vector<uint8_t>* cid = DataHolderHelper::find_binary_property_value(handshake_message_in, "c.id");
    if (cid == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.id");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    //! Release the memory in case of having an old certificate
    if (rih->cert_ != nullptr) {
        X509_free(rih->cert_);
        rih->cert_ = nullptr;
    }
    if (rih->intermediate_certs_ != nullptr) {
        sk_X509_pop_free(rih->intermediate_certs_, X509_free);
        rih->intermediate_certs_ = nullptr;
    }

    rih->cert_ = load_certificate(*cid, &rih->intermediate_certs_);

    if (rih->cert_ == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot load certificate");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    X509_NAME* cert_sn = X509_get_subject_name(rih->cert_);
    assert(cert_sn != nullptr);
    char* cert_sn_str = X509_NAME_oneline(cert_sn, 0, 0);
    assert(cert_sn_str != nullptr);
    if ((!rih->cert_sn_.empty()) && (rih->cert_sn_.compare(cert_sn_str) != 0)) {
        OPENSSL_free(cert_sn_str);
        WARNING_SECURITY_LOGGING("PKIDH", "Certificated subject name invalid");
        return ValidationResult_t::VALIDATION_FAILED;
    }
    OPENSSL_free(cert_sn_str);
    BIO* cert_sn_rfc2253_str = BIO_new(BIO_s_mem());
    (void)X509_NAME_print_ex(cert_sn_rfc2253_str, cert_sn, 0, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
    const int bufsize = 1024;
    char buffer[1024];
    int str_length = BIO_read(cert_sn_rfc2253_str, buffer, bufsize);
    (void)BIO_free(cert_sn_rfc2253_str);
    if (str_length < 0) {
        WARNING_SECURITY_LOGGING("PKIDH", "Error cert_sn_rfc2253 length");
        return ValidationResult_t::VALIDATION_FAILED;
    }
    (void)rih->cert_sn_rfc2253_.assign(buffer, str_length);

    if (!verify_certificate(lih->store_, rih->cert_, lih->there_are_crls_, rih->intermediate_certs_, exception)) {
        WARNING_SECURITY_LOGGING("PKIDH", std::string("Error verifying certificate:") + exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // c.perm
    if (lih->permissions_credential_token_.class_id().compare("DDS:Access:PermissionsCredential") == 0) {
        const std::vector<uint8_t>* perm = DataHolderHelper::find_binary_property_value(handshake_message_in, "c.perm");

        if (perm == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.perm");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        rih->permissions_credential_token_.class_id("DDS:Access:PermissionsCredential");
        Property permission_file;
        permission_file.name("dds.perm.cert");
        (void)permission_file.value().assign(perm->begin(), perm->end());
        rih->permissions_credential_token_.properties().push_back(std::move(permission_file));
    }

    const std::vector<uint8_t>* pdata = DataHolderHelper::find_binary_property_value(handshake_message_in, "c.pdata");

    if (pdata == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.pdata");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    GUID_t participant_guid;
    CDRMessage_t cdr_pdata(0);
    cdr_pdata.wraps = true;
    cdr_pdata.msg_endian = BIGEND;
    cdr_pdata.length = (uint32_t)pdata->size();
    cdr_pdata.max_size = (uint32_t)pdata->size();
    cdr_pdata.buffer = (octet*)pdata->data();

    if (!ParameterList::read_guid_from_cdr_msg(cdr_pdata, edds::dds::PID_PARTICIPANT_GUID, participant_guid)) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot deserialize ParticipantProxyData in property c.pdata");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if ((participant_guid.guidPrefix.value[8] & 0x80) != 0x80) {
        DEBUG_SECURITY_LOGGING("PKIDH", "Bad participant_key's first bit in c.pdata");
        // return ValidationResult_t::VALIDATION_FAILED;
    }

    unsigned char md[SHA256_DIGEST_LENGTH];
    uint32_t length = 0;

    if ((!X509_NAME_digest(cert_sn, EVP_sha256(), md, &length)) || (length != SHA256_DIGEST_LENGTH)) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot generate SHA256 of subject name");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    unsigned char bytes[4] {static_cast<unsigned char>((participant_guid.guidPrefix.value[8] << 1) |
                                                       (participant_guid.guidPrefix.value[9] >> 7)),
                            static_cast<unsigned char>((participant_guid.guidPrefix.value[9] << 1) |
                                                       (participant_guid.guidPrefix.value[10] >> 7)),
                            static_cast<unsigned char>((participant_guid.guidPrefix.value[10] << 1) |
                                                       (participant_guid.guidPrefix.value[11] >> 7)),
                            static_cast<unsigned char>(participant_guid.guidPrefix.value[11] << 1)};
    md[sizeof(bytes) - 1] &= 0xFE;

    if (memcmp(md, bytes, sizeof(bytes)) != 0) {
        DEBUG_SECURITY_LOGGING("PKIDH", "Bad participant_key's 47bits in c.pdata");
        // return ValidationResult_t::VALIDATION_FAILED;
    }

    // c.dsign_algo
    const std::vector<uint8_t>* dsign_algo =
        DataHolderHelper::find_binary_property_value(handshake_message_in, "c.dsign_algo");

    if (dsign_algo == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.dsign_algo");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // Check signature algorithm
    std::string s_dsign_algo(dsign_algo->begin(), dsign_algo->end());
    if ((s_dsign_algo.compare(evbs::ertps::rtps::security::RSA_SHA256) != 0) &&
        (s_dsign_algo.compare(evbs::ertps::rtps::security::ECDSA_SHA256) != 0) &&
        (s_dsign_algo.compare(evbs::ertps::rtps::security::ECDSA_SHA384) != 0)) {
        WARNING_SECURITY_LOGGING("PKIDH", std::string("Not supported signature algorithm (") + s_dsign_algo + ")");
        return ValidationResult_t::VALIDATION_FAILED;
    }
    rih->sign_alg_ = std::move(s_dsign_algo);

    // c.kagree_algo
    const std::vector<uint8_t>* kagree_algo =
        DataHolderHelper::find_binary_property_value(handshake_message_in, "c.kagree_algo");

    if (kagree_algo == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property c.kagree_algo");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // Check key agreement algorithm
    std::string s_kagree_algo(kagree_algo->begin(), kagree_algo->end());
    if (s_kagree_algo.compare(handshake_handle->kagree_alg_) != 0) {
        WARNING_SECURITY_LOGGING("PKIDH", std::string("Invalid key agreement algorithm. Received ") + s_kagree_algo +
                                              ", expected " + handshake_handle->kagree_alg_);
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // hash_c2
    BinaryProperty* hash_c2 = DataHolderHelper::find_binary_property(handshake_message_in, "hash_c2");

    if (hash_c2 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property hash_c2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (hash_c2->value().size() != SHA256_DIGEST_LENGTH) {
        WARNING_SECURITY_LOGGING("PKIDH", "Wrong size of hash_c2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    uint32_t digestInLen =
        static_cast<uint32_t>(BinaryPropertyHelper::serialized_size(handshake_message_in.binary_properties()));
    CDRMessage_t cdrmessage(digestInLen + 3);
    cdrmessage.msg_endian = BIGEND;
    (void)CDRMessage::addBinaryPropertySeq(&cdrmessage, handshake_message_in.binary_properties(), "c.", false);

    if (!EVP_Digest(cdrmessage.buffer, cdrmessage.length, md, NULL, EVP_sha256(), NULL)) {
        exception = _SecurityException_("Cannot generate SHA256 of request");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (memcmp(md, hash_c2->value().data(), SHA256_DIGEST_LENGTH) != 0) {
        WARNING_SECURITY_LOGGING("PKIDH", "Wrong hash_c2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // dh2
    BinaryProperty* dh2 = DataHolderHelper::find_binary_property(handshake_message_in, "dh2");
    if (dh2 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dh2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    int kagree_kind = get_dh_type(s_kagree_algo);

    if ((handshake_handle->peerkeys_ = generate_dh_peer_key(dh2->value(), exception, kagree_kind)) == nullptr) {
        exception = _SecurityException_("Cannot store peer key from dh2");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* challenge2 = DataHolderHelper::find_binary_property(handshake_message_in, "challenge2");

    if (challenge2 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property challenge2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // hash_c1
    BinaryProperty* hash_c1 = DataHolderHelper::find_binary_property(handshake_message_in, "hash_c1");

    if (hash_c1 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property hash_c1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    const std::vector<uint8_t>* hash_c1_request =
        DataHolderHelper::find_binary_property_value(handshake_handle->handshake_message_, "hash_c1");

    if (hash_c1_request == nullptr) {
        exception = _SecurityException_("Cannot find property hash_c1 in request message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (hash_c1->value() != *hash_c1_request) {
        WARNING_SECURITY_LOGGING("PKIDH", "Invalid property hash_c1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // dh1
    BinaryProperty* dh1 = DataHolderHelper::find_binary_property(handshake_message_in, "dh1");

    if (dh1 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dh1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    const std::vector<uint8_t>* dh1_request =
        DataHolderHelper::find_binary_property_value(handshake_handle->handshake_message_, "dh1");

    if (dh1_request == nullptr) {
        exception = _SecurityException_("Cannot find property dh1 in request message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (dh1->value() != *dh1_request) {
        WARNING_SECURITY_LOGGING("PKIDH", "Invalid property dh1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* challenge1 = DataHolderHelper::find_binary_property(handshake_message_in, "challenge1");

    if (challenge1 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property challenge1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    const std::vector<uint8_t>* challenge1_request =
        DataHolderHelper::find_binary_property_value(handshake_handle->handshake_message_, "challenge1");

    if (challenge1_request == nullptr) {
        exception = _SecurityException_("Cannot find property challenge1 in request message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (challenge1->value() != *challenge1_request) {
        WARNING_SECURITY_LOGGING("PKIDH", "Invalid property challenge1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    const std::vector<uint8_t>* signature =
        DataHolderHelper::find_binary_property_value(handshake_message_in, "signature");

    if (signature == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property signature");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // signature
    CDRMessage_t cdrmessage2(
        static_cast<uint32_t>(BinaryPropertyHelper::serialized_size(handshake_message_in.binary_properties())));
    cdrmessage2.msg_endian = BIGEND;
    // add sequence length
    (void)CDRMessage::addUInt32(&cdrmessage2, 6);
    // add hash_c2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *hash_c2);
    // add challenge2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *challenge2);
    // add dh2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *dh2);
    // add challenge1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *challenge1);
    // add dh1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *dh1);
    // add hash_c1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *hash_c1, false);

    unsigned char* buf = cdrmessage2.buffer;
    size_t len = cdrmessage2.length;
#if VBSAUTH
    // vbsauth need sha256 one more time
    unsigned char hash[SHA256_DIGEST_LENGTH];
    if (is_use_vbsauth) {
        (void)SHA256(buf, len, hash);
        buf = hash;
        len = sizeof(hash);
    }
#endif
    if (!check_sign_sha256(rih->cert_, buf, len, *signature, exception)) {
        WARNING_SECURITY_LOGGING("PKIDH", "Error verifying signature");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // Generate handshake final message token.
    HandshakeMessageToken final_message;
    final_message.binary_properties().clear();
    final_message.class_id("DDS:Auth:PKI-DH:1.0+Final");

    BinaryProperty bproperty;

    // hash_c1
    bproperty.name("hash_c1");
    bproperty.value(std::move(hash_c1->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // hash_c2
    bproperty.name("hash_c2");
    bproperty.value(std::move(hash_c2->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // dh1
    bproperty.name("dh1");
    bproperty.value(std::move(dh1->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // dh2
    bproperty.name("dh2");
    bproperty.value(std::move(dh2->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // challenge1
    bproperty.name("challenge1");
    bproperty.value(std::move(challenge1->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // challenge2
    bproperty.name("challenge2");
    bproperty.value(std::move(challenge2->value()));
    bproperty.propagate(true);
    final_message.binary_properties().push_back(std::move(bproperty));

    // signature
    cdrmessage2.length = 0;
    cdrmessage2.pos = 0;
    // add sequence length
    (void)CDRMessage::addUInt32(&cdrmessage2, 6);
    // add hash_c1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                        *DataHolderHelper::find_binary_property(final_message, "hash_c1"));
    // add challenge1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                        *DataHolderHelper::find_binary_property(final_message, "challenge1"));
    // add dh1
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *DataHolderHelper::find_binary_property(final_message, "dh1"));
    // add challenge2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2,
                                        *DataHolderHelper::find_binary_property(final_message, "challenge2"));
    // add dh2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *DataHolderHelper::find_binary_property(final_message, "dh2"));
    // add hash_c2
    (void)CDRMessage::addBinaryProperty(&cdrmessage2, *DataHolderHelper::find_binary_property(final_message, "hash_c2"),
                                        false);

    bproperty.name("signature");
    bproperty.propagate(true);
    if (sign_sha256(lih->pkey_, cdrmessage2.buffer, cdrmessage2.length, bproperty.value(), exception, *this)) {
        final_message.binary_properties().push_back(std::move(bproperty));

        handshake_handle->sharedsecret_ = std::dynamic_pointer_cast<SharedSecretHandle>(
            generate_sharedsecret(handshake_handle->dhkeys_, handshake_handle->peerkeys_, exception));

        if (handshake_handle->sharedsecret_ != nullptr) {
            // Save challenge1 y challenge2 in sharedsecret
            (*handshake_handle->sharedsecret_)
                ->data_.emplace_back(SharedSecret::BinaryData(
                    "Challenge1", *DataHolderHelper::find_binary_property_value(final_message, "challenge1")));
            (*handshake_handle->sharedsecret_)
                ->data_.emplace_back(SharedSecret::BinaryData(
                    "Challenge2", *DataHolderHelper::find_binary_property_value(final_message, "challenge2")));

            handshake_handle->handshake_message_ = std::move(final_message);
            *handshake_message_out = &handshake_handle->handshake_message_;

            return ValidationResult_t::VALIDATION_OK_WITH_FINAL_MESSAGE;
        }
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::process_handshake_request_mvbs(HandshakeMessageToken** handshake_message_out,
                                                         HandshakeMessageToken&& handshake_message_in,
                                                         PKIHandshakeHandle& handshake_handle,
                                                         SecurityException& exception) {
    const PKIIdentityHandle& lih = *handshake_handle->local_identity_handle_;
    PKIIdentityHandle& rih = *handshake_handle->remote_identity_handle_;

    // Check TokenMessage
    if (handshake_message_in.class_id().compare("DDS:Auth:MVBS+Reply") != 0) {
        WARNING_SECURITY_LOGGING("PKIDH",
                                 std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // deal reply
    const std::vector<uint8_t>* remote_mvbs_q =
        DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.msg");
    if (remote_mvbs_q == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds msg");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (lih->mvbs_sign_alg_.compare("ED25519") == 0 || (lih->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0)) {
        if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
            const std::vector<uint8_t>* remote_ed25519_pub =
                DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.pub");
            if (remote_ed25519_pub == nullptr) {
                WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds msg");
                return ValidationResult_t::VALIDATION_FAILED;
            }

            rih->ed25519_remote_public_pkey_ = coverVectortoPem_base64(*remote_ed25519_pub, exception);
            if (rih->ed25519_remote_public_pkey_ == NULL) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        const std::vector<uint8_t>* remote_sign =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.sign");
        if (remote_sign == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds.sign");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // verify
        std::vector<uint8_t> p2verify(MVBS_SEC_Q_LEN);
        p2verify.assign(rih->msec_q.begin(), rih->msec_q.end());
        generate_secret_P(rih->participant_key_, lih->participant_key_, p2verify);

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
            if (!ed25519_verify_message(rih->ed25519_remote_public_pkey_, p2verify, *remote_sign, exception)) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        } else {
            if (!mvbs_hmac_verify_message(lih->mhmac_key, p2verify, *remote_sign, exception)) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }
    } else {
        EMERGENCY_SECURITY_LOGGING("PKIDH", "no find mvbs sign alg");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    const char* buffer = "emailAddreee=VBS@lixiang.com,CN=LiDDS_MVBS_2729,OU=LiVBS,O=LiAuto,ST=Beijing,C=CN";
    (void)rih->cert_sn_rfc2253_.assign(buffer, strlen(buffer));

    // Generate handshake final message token.
    HandshakeMessageToken final_message;
    final_message.binary_properties().clear();
    final_message.class_id("DDS:Auth:MVBS+Final");

    // send finial
    BinaryProperty bproperty;
    if (lih->mvbs_sign_alg_.compare("ED25519") == 0 || (lih->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0)) {
        // sign
        std::vector<uint8_t> p2sign(MVBS_SEC_Q_LEN), sign_data;
        p2sign.assign(remote_mvbs_q->begin(), remote_mvbs_q->end());

        generate_secret_P(lih->participant_key_, rih->participant_key_, p2sign);

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
            if (!ed25519_sign_message(lih->ed25519_local_private_pkey_, p2sign, sign_data, exception)) {
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        } else {
            if (!mvbs_hmac_message(lih->mhmac_key, p2sign, sign_data, exception)) {
                EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

        bproperty.name("dds.sign");
        bproperty.value().assign(sign_data.data(), sign_data.data() + sign_data.size());
        bproperty.propagate(true);
    } else {
        EMERGENCY_SECURITY_LOGGING("PKIDH", "no find mvbs sign alg");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    final_message.binary_properties().push_back(std::move(bproperty));

    handshake_handle->sharedsecret_ = std::dynamic_pointer_cast<SharedSecretHandle>(generate_sharedsecret_mvbs());

    handshake_handle->handshake_message_ = std::move(final_message);
    *handshake_message_out = &handshake_handle->handshake_message_;

    return ValidationResult_t::VALIDATION_OK_WITH_FINAL_MESSAGE;
}

ValidationResult_t PKIDH::process_handshake_reply(HandshakeMessageToken** /*handshake_message_out*/,
                                                  HandshakeMessageToken&& handshake_message_in,
                                                  PKIHandshakeHandle& handshake_handle, SecurityException& exception) {
    PKIIdentityHandle& rih = *handshake_handle->remote_identity_handle_;

    // Check TokenMessage
    if (handshake_message_in.class_id().compare("DDS:Auth:PKI-DH:1.0+Final") != 0) {
        WARNING_SECURITY_LOGGING("PKIDH",
                                 std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // Check incoming handshake.

    // challenge1 (mandatory)
    BinaryProperty* challenge1 = DataHolderHelper::find_binary_property(handshake_message_in, "challenge1");
    if (challenge1 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property challenge1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    std::vector<uint8_t>* challenge1_reply =
        DataHolderHelper::find_binary_property_value(handshake_handle->handshake_message_, "challenge1");
    if (challenge1_reply == nullptr) {
        exception = _SecurityException_("Cannot find property challenge1 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (challenge1->value() != *challenge1_reply) {
        WARNING_SECURITY_LOGGING("PKIDH", "Invalid challenge1");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // challenge2 (mandatory)
    BinaryProperty* challenge2 = DataHolderHelper::find_binary_property(handshake_message_in, "challenge2");
    if (challenge2 == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property challenge2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    std::vector<uint8_t>* challenge2_reply =
        DataHolderHelper::find_binary_property_value(handshake_handle->handshake_message_, "challenge2");
    if (challenge2_reply == nullptr) {
        exception = _SecurityException_("Cannot find property challenge2 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (challenge2->value() != *challenge2_reply) {
        WARNING_SECURITY_LOGGING("PKIDH", "Invalid challenge2");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // signature (mandatory)
    const std::vector<uint8_t>* signature =
        DataHolderHelper::find_binary_property_value(handshake_message_in, "signature");
    if (signature == nullptr) {
        WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property signature");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    // hash_c1 (optional)
    BinaryProperty* hash_c1_reply =
        DataHolderHelper::find_binary_property(handshake_handle->handshake_message_, "hash_c1");
    if (hash_c1_reply == nullptr) {
        exception = _SecurityException_("Cannot find property hash_c1 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* hash_c1 = DataHolderHelper::find_binary_property(handshake_message_in, "hash_c1");
    if (hash_c1 != nullptr) {
        if (hash_c1->value() != hash_c1_reply->value()) {
            WARNING_SECURITY_LOGGING("PKIDH", "Invalid hash_c1");
        }
    }

    // hash_c2 (optional)
    BinaryProperty* hash_c2_reply =
        DataHolderHelper::find_binary_property(handshake_handle->handshake_message_, "hash_c2");
    if (hash_c2_reply == nullptr) {
        exception = _SecurityException_("Cannot find property hash_c2 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* hash_c2 = DataHolderHelper::find_binary_property(handshake_message_in, "hash_c2");
    if (hash_c2 != nullptr) {
        if (hash_c2->value() != hash_c2_reply->value()) {
            WARNING_SECURITY_LOGGING("PKIDH", "Invalid hash_c2");
        }
    }

    // dh1 (optional)
    BinaryProperty* dh1_reply = DataHolderHelper::find_binary_property(handshake_handle->handshake_message_, "dh1");
    if (dh1_reply == nullptr) {
        exception = _SecurityException_("Cannot find property dh1 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* dh1 = DataHolderHelper::find_binary_property(handshake_message_in, "dh1");
    if (dh1 != nullptr) {
        if (dh1->value() != dh1_reply->value()) {
            WARNING_SECURITY_LOGGING("PKIDH", "Invalid dh1");
        }
    }

    // dh2 (optional)
    BinaryProperty* dh2_reply = DataHolderHelper::find_binary_property(handshake_handle->handshake_message_, "dh2");
    if (dh2_reply == nullptr) {
        exception = _SecurityException_("Cannot find property dh2 in reply message");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    BinaryProperty* dh2 = DataHolderHelper::find_binary_property(handshake_message_in, "dh2");
    if (dh2 != nullptr) {
        if (dh2->value() != dh2_reply->value()) {
            WARNING_SECURITY_LOGGING("PKIDH", "Invalid dh2");
        }
    }

    // signature
    CDRMessage_t cdrmessage(static_cast<uint32_t>(
        BinaryPropertyHelper::serialized_size(handshake_handle->handshake_message_.binary_properties())));
    cdrmessage.msg_endian = BIGEND;
    // add sequence length
    (void)CDRMessage::addUInt32(&cdrmessage, 6);
    // add hash_c1
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *hash_c1_reply);
    // add challenge1
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *challenge1);
    // add dh1
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *dh1_reply);
    // add challenge2
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *challenge2);
    // add dh2
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *dh2_reply);
    // add hash_c2
    (void)CDRMessage::addBinaryProperty(&cdrmessage, *hash_c2_reply, false);

    unsigned char* buf = cdrmessage.buffer;
    size_t len = cdrmessage.length;
#if VBSAUTH
    // vbsauth need sha256 one more time
    unsigned char hash[SHA256_DIGEST_LENGTH];
    if (is_use_vbsauth) {
        (void)SHA256(buf, len, hash);
        buf = hash;
        len = sizeof(hash);
    }
#endif
    if (!check_sign_sha256(rih->cert_, buf, len, *signature, exception)) {
        WARNING_SECURITY_LOGGING("PKIDH", "Error verifying signature");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    handshake_handle->sharedsecret_ = std::dynamic_pointer_cast<SharedSecretHandle>(
        generate_sharedsecret(handshake_handle->dhkeys_, handshake_handle->peerkeys_, exception));

    if (handshake_handle->sharedsecret_ != nullptr) {
        // Save challenge1 y challenge2 in sharedsecret
        (*handshake_handle->sharedsecret_)
            ->data_.emplace_back(SharedSecret::BinaryData("Challenge1", challenge1->value()));
        (*handshake_handle->sharedsecret_)
            ->data_.emplace_back(SharedSecret::BinaryData("Challenge2", challenge2->value()));

        return ValidationResult_t::VALIDATION_OK;
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::process_handshake_reply_mvbs(HandshakeMessageToken** /*handshake_message_out*/,
                                                       HandshakeMessageToken&& handshake_message_in,
                                                       PKIHandshakeHandle& handshake_handle,
                                                       SecurityException& exception) {
    const PKIIdentityHandle& lih = *handshake_handle->local_identity_handle_;
    PKIIdentityHandle& rih = *handshake_handle->remote_identity_handle_;

    // Check TokenMessage
    if (handshake_message_in.class_id().compare("DDS:Auth:MVBS+Final") != 0) {
        WARNING_SECURITY_LOGGING("PKIDH",
                                 std::string("Bad HandshakeMessageToken (") + handshake_message_in.class_id() + ")");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (lih->mvbs_sign_alg_.compare("ED25519") == 0 || (lih->mvbs_sign_alg_.compare("MVBS_SIMPLE") == 0)) {
        const std::vector<uint8_t>* remote_sign =
            DataHolderHelper::find_binary_property_value(handshake_message_in, "dds.sign");
        if (remote_sign == nullptr) {
            WARNING_SECURITY_LOGGING("PKIDH", "Cannot find property dds.sign");
            return ValidationResult_t::VALIDATION_FAILED;
        }

        // verify
        std::vector<uint8_t> p2verify(MVBS_SEC_Q_LEN);
        p2verify.assign(rih->msec_q.begin(), rih->msec_q.end());
        generate_secret_P(rih->participant_key_, lih->participant_key_, p2verify);

        if (lih->mvbs_sign_alg_.compare("ED25519") == 0) {
            if (!ed25519_verify_message(rih->ed25519_remote_public_pkey_, p2verify, *remote_sign, exception)) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        } else {
            if (!mvbs_hmac_verify_message(lih->mhmac_key, p2verify, *remote_sign, exception)) {
                WARNING_SECURITY_LOGGING("PKIDH", exception.what());
                return ValidationResult_t::VALIDATION_FAILED;
            }
        }

    } else {
        EMERGENCY_SECURITY_LOGGING("PKIDH", "no find mvbs sign alg");
        return ValidationResult_t::VALIDATION_FAILED;
    }

    handshake_handle->sharedsecret_ = std::dynamic_pointer_cast<SharedSecretHandle>(generate_sharedsecret_mvbs());

    return ValidationResult_t::VALIDATION_OK;
}

std::shared_ptr<SecretHandle> PKIDH::get_shared_secret(const HandshakeHandle& handshake_handle,
                                                       SecurityException& exception) const {
    const PKIHandshakeHandle& handshake = PKIHandshakeHandle::narrow(handshake_handle);

    if (!handshake.nil()) {
        auto secret = get_shared_secret(SharedSecretHandle::nil_handle, exception);
        auto sharedsecret = std::dynamic_pointer_cast<SharedSecretHandle>(secret);
        (*sharedsecret)->data_ = (*handshake->sharedsecret_)->data_;
        return secret;
    }

    // create ad hoc deleter because this object can only be created/release from the friend factory
    auto p = new (std::nothrow) SharedSecretHandle;
    return std::dynamic_pointer_cast<SecretHandle>(
        std::shared_ptr<SharedSecretHandle>(p, [](SharedSecretHandle* p) { delete p; }));
}

bool PKIDH::set_listener(AuthenticationListener* /*listener*/, SecurityException& /*exception*/) {
    return false;
}

bool PKIDH::get_identity_token(IdentityToken** identity_token, const IdentityHandle& handle,
                               SecurityException& /*exception*/) {
    const PKIIdentityHandle& ihandle = PKIIdentityHandle::narrow(handle);

    if (!ihandle.nil()) {
        *identity_token = new IdentityToken(ihandle->identity_token_);
        return true;
    }

    return false;
}

bool PKIDH::return_identity_token(IdentityToken* token, SecurityException& /*exception*/) {
    delete token;
    return true;
}

bool PKIDH::return_handshake_handle(HandshakeHandle* handshake_handle, SecurityException& /*exception*/) {
    PKIHandshakeHandle* handle = &PKIHandshakeHandle::narrow(*handshake_handle);

    if (!handle->nil()) {
        delete handle;
        return true;
    }

    return false;
}

IdentityHandle* PKIDH::get_identity_handle(SecurityException&) {
    return new (std::nothrow) PKIIdentityHandle();
}

bool PKIDH::return_identity_handle(IdentityHandle* identity_handle, SecurityException& /*exception*/) {
    PKIIdentityHandle* handle = &PKIIdentityHandle::narrow(*identity_handle);

    if (!handle->nil()) {
        delete handle;
        return true;
    }

    return false;
}

bool PKIDH::return_sharedsecret_handle(std::shared_ptr<SecretHandle>& sharedsecret_handle,
                                       SecurityException& /*exception*/) const {
    sharedsecret_handle.reset();
    return true;
}

bool PKIDH::set_permissions_credential_and_token(IdentityHandle& identity_handle,
                                                 PermissionsCredentialToken& permissions_credential_token,
                                                 SecurityException& exception) {
    PKIIdentityHandle& ihandle = PKIIdentityHandle::narrow(identity_handle);

    if (!ihandle.nil()) {
        ihandle->permissions_credential_token_ = permissions_credential_token;
        return true;
    } else {
        exception = _SecurityException_("Invalid identity handle");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
    }

    return false;
}

bool PKIDH::get_authenticated_peer_credential_token(PermissionsCredentialToken** token,
                                                    const IdentityHandle& identity_handle,
                                                    SecurityException& exception) {
    const PKIIdentityHandle& handle = PKIIdentityHandle::narrow(identity_handle);

    if (!handle.nil()) {
        *token = new PermissionsCredentialToken(handle->permissions_credential_token_);
        return true;
    } else {
        exception = _SecurityException_("Invalid handshake handle");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
    }

    return false;
}

bool PKIDH::return_authenticated_peer_credential_token(PermissionsCredentialToken* token, SecurityException&) {
    delete token;
    return true;
}

bool PKIDH::check_guid_comes_from(IdentityHandle* identity_handle, const GUID_t& adjusted, const GUID_t& original) {
    SecurityException exception;

    if (identity_handle != nullptr) {
        PKIIdentityHandle* pkiih = &PKIIdentityHandle::narrow(*identity_handle);
        GUID_t adjusted_original_guid;

        if (pkiih != nullptr && !(*pkiih).nil() && (*pkiih)->cert_ != nullptr) {
            adjust_participant_key((*pkiih)->cert_, original, adjusted_original_guid, exception);
            return adjusted == adjusted_original_guid;
        } else {
            exception = _SecurityException_("Invalid PKI Identity handle or Invalid Certificate");
            EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        }

    } else {
        exception = _SecurityException_("Invalid Identity handle");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
    }

    return adjusted == original;
}

std::shared_ptr<SecretHandle> PKIDH::generate_fake_sharedsecret(const std::vector<uint8_t>& shared_key,
                                                                SecurityException& exception) const {
    std::shared_ptr<SharedSecretHandle> handle;

    SharedSecret::BinaryData data;
    data.name("SharedSecret");
    data.value().resize(32);

    if (shared_key.size() >= 32) {
        data.value().assign(shared_key.begin(), shared_key.begin() + 32);
    } else {
        logInfo(SECURITY, "shared_key size error:" << shared_key.size());
        std::vector<uint8_t> key(32);
        if (RAND_bytes((unsigned char*)(key.data()), key.size()) == 1) {
            logInfo(SECURITY, "RAND_bytes error");
        }
        data.value().assign(key.begin(), key.begin() + 32);
    }

    handle =
        std::dynamic_pointer_cast<SharedSecretHandle>(get_shared_secret(SharedSecretHandle::nil_handle, exception));
    (*handle)->data_.push_back(std::move(data));

    return std::dynamic_pointer_cast<SecretHandle>(handle);
}

ValidationResult_t PKIDH::begin_fake_handshake_reply(HandshakeHandle** handshake_handle,
                                                     IdentityHandle& initiator_identity_handle,
                                                     const IdentityHandle& replier_identity_handle,
                                                     const CDRMessage_t& cdr_participant_data,
                                                     SecurityException& exception) {
    assert(handshake_handle);
    // assert(handshake_message_out);
    assert(initiator_identity_handle.nil() == false);
    assert(replier_identity_handle.nil() == false);

    const PKIIdentityHandle& lih = PKIIdentityHandle::narrow(replier_identity_handle);
    PKIIdentityHandle& rih = PKIIdentityHandle::narrow(initiator_identity_handle);

    if (lih.nil() || rih.nil()) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (cdr_participant_data.length == 0) {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("PKIDH", exception.what());
        return ValidationResult_t::VALIDATION_FAILED;
    }

    if (!rih->ismvbs_sec) {
        rih->sign_alg_ = std::move(evbs::ertps::rtps::security::ECDSA_SHA256);
        rih->kagree_alg_ = std::move(evbs::ertps::rtps::security::ECDH_prime256v1);

        // Generate handshake reply message token.
        PKIHandshakeHandle* handshake_handle_aux = new PKIHandshakeHandle();
        (*handshake_handle_aux)->kagree_alg_ = rih->kagree_alg_;
        (*handshake_handle_aux)->local_identity_handle_ = &lih;
        (*handshake_handle_aux)->remote_identity_handle_ = &rih;
        *handshake_handle = handshake_handle_aux;

        return ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::process_fake_handshake(uint32_t auth_status, const std::vector<uint8_t>& shared_key,
                                                 HandshakeHandle& handshake_handle, SecurityException& exception) {
    ValidationResult_t returnedValue = ValidationResult_t::VALIDATION_FAILED;

    PKIHandshakeHandle& handshake = PKIHandshakeHandle::narrow(handshake_handle);

    if (!handshake.nil()) {
        if (auth_status == 5) {
            returnedValue = process_fake_handshake_request(shared_key, handshake, exception);
        } else if (auth_status == 6) {
            returnedValue = process_fake_handshake_reply(shared_key, handshake, exception);
        } else {
            WARNING_SECURITY_LOGGING("PKIDH", std::string("Handshake message not supported (") +
                                                  handshake->handshake_message_.class_id() + ")");
        }
    }

    return returnedValue;
}

ValidationResult_t PKIDH::process_fake_handshake_request(const std::vector<uint8_t>& shared_key,
                                                         PKIHandshakeHandle& handshake_handle,
                                                         SecurityException& exception) {
    PKIIdentityHandle& rih = *handshake_handle->remote_identity_handle_;

    rih->sign_alg_ = std::move(evbs::ertps::rtps::security::ECDSA_SHA256);

    // Check key agreement algorithm
    std::string s_kagree_algo = "ECDH+prime256v1-CEUM";
    std::vector<uint8_t> challenge1 = {0xd0, 0x43, 0x4f, 0x6c, 0x25, 0x6b, 0x92, 0xbf, 0x66, 0x41, 0x84,
                                       0xaf, 0x79, 0xf7, 0xda, 0x7f, 0x5f, 0x23, 0xf9, 0x02, 0x22, 0x5e,
                                       0xf6, 0x5d, 0x54, 0x2d, 0x53, 0xb6, 0xa0, 0x24, 0xee, 0x7c};
    std::vector<uint8_t> challenge2 = {0x8e, 0x57, 0x10, 0x46, 0x50, 0x25, 0xc5, 0xe5, 0x79, 0x94, 0xa9,
                                       0xc1, 0xf0, 0x4b, 0xd8, 0xeb, 0x8a, 0xb1, 0x62, 0x6d, 0x42, 0x7d,
                                       0xd6, 0x8f, 0xc8, 0x4b, 0x40, 0x33, 0xf6, 0x23, 0x29, 0xf1};
    {
        handshake_handle->sharedsecret_ =
            std::dynamic_pointer_cast<SharedSecretHandle>(generate_fake_sharedsecret(shared_key, exception));

        if (handshake_handle->sharedsecret_ != nullptr) {
            // Save challenge1 y challenge2 in sharedsecret
            (*handshake_handle->sharedsecret_)->data_.emplace_back(SharedSecret::BinaryData("Challenge1", challenge1));
            (*handshake_handle->sharedsecret_)->data_.emplace_back(SharedSecret::BinaryData("Challenge2", challenge2));

            return ValidationResult_t::VALIDATION_OK_WITH_FINAL_MESSAGE;
        }
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

ValidationResult_t PKIDH::process_fake_handshake_reply(const std::vector<uint8_t>& shared_key,
                                                       PKIHandshakeHandle& handshake_handle,
                                                       SecurityException& exception) {
    std::vector<uint8_t> challenge1 = {0xd0, 0x43, 0x4f, 0x6c, 0x25, 0x6b, 0x92, 0xbf, 0x66, 0x41, 0x84,
                                       0xaf, 0x79, 0xf7, 0xda, 0x7f, 0x5f, 0x23, 0xf9, 0x02, 0x22, 0x5e,
                                       0xf6, 0x5d, 0x54, 0x2d, 0x53, 0xb6, 0xa0, 0x24, 0xee, 0x7c};
    std::vector<uint8_t> challenge2 = {0x8e, 0x57, 0x10, 0x46, 0x50, 0x25, 0xc5, 0xe5, 0x79, 0x94, 0xa9,
                                       0xc1, 0xf0, 0x4b, 0xd8, 0xeb, 0x8a, 0xb1, 0x62, 0x6d, 0x42, 0x7d,
                                       0xd6, 0x8f, 0xc8, 0x4b, 0x40, 0x33, 0xf6, 0x23, 0x29, 0xf1};

    handshake_handle->sharedsecret_ =
        std::dynamic_pointer_cast<SharedSecretHandle>(generate_fake_sharedsecret(shared_key, exception));

    if (handshake_handle->sharedsecret_ != nullptr) {
        // Save challenge1 y challenge2 in sharedsecret
        (*handshake_handle->sharedsecret_)->data_.emplace_back(SharedSecret::BinaryData("Challenge1", challenge1));
        (*handshake_handle->sharedsecret_)->data_.emplace_back(SharedSecret::BinaryData("Challenge2", challenge2));

        return ValidationResult_t::VALIDATION_OK;
    }

    ERR_clear_error();

    return ValidationResult_t::VALIDATION_FAILED;
}

}  // namespace rtps
}  // namespace ertps
}  // namespace evbs
